10月 312013
 

DbContextでの話。

普通はDbContextから取得したデータを更新すれば良い。
[csharp]
using (var context = new Entities())
{
var hoge= context.Hoge.Find(“id的な”);
hoge.Fuga = “New!”;
context.SaveChanges();
}
[/csharp]

これはDbContextに変更追跡機能があるため可能な事。
DbContextのライフサイクル外から受け取ったEntityオブジェクトなんかはただのPOCOであり、どう変更されたかなんてDbContextは知らない。
DataSetなんかは、DataTable自体が変更追跡機能持っててシリアライズもできたのだけど…

自己追跡エンティティ(STE)なんかもあるけど、Not Recommendedとされているし、EF6やVS2013ではもう使えない。
EF4から導入されたばかりなのに短い寿命でしたね…

んで、WCFなんかで外部から受け取ったデータは当然変更追跡の対象外なため、Attachとかしないとダメなことは想像付く。
でもAttachしただけではUnchangedな状態なので、変更してくれない。
ではどうすれば良いかというと、どうやらModified状態に変更してしまえば勝手に更新してくれるようだ。
[csharp]
public void Update(Hoge hoge){
using (var context = new Entities())
{
context.Hoge.Attach(hoge);
context.Entry(hoge).State = EntityState.Modified;
context.SaveChanges();
}
}
[/csharp]
削除はAttachしてからRemoveすればOK。
[csharp]
public void Remove(Hoge hoge){
using (var context = new Entities())
{
context.Hoge.Attach(hoge);
context.Hoge.Remove(hoge);
context.SaveChanges();
}
}
[/csharp]

ちなみにナビゲーションプロパティでIncludeされてる関連オブジェクトがある場合で、外部キーの値を変更したのに、関連オブジェクトは変更前のままとかいう場合、Attachすると死ぬ。
[csharp]
//どっかで読み込んだ
context.Hoge
.AsNoTracking()
.Include(x => x.Piyo)
;
[/csharp]
[csharp]
//どっかで外部参照のキー値を更新した
hoge.PiyoId = “new id”; //※hoge.Piyoは変更前のまま
[/csharp]
[csharp]
//そのままAttachすると死ぬ
context.Hoge.Attach(hoge);
[/csharp]
この場合、どうやらナビゲーションプロパティをnullにしてしまえばAttachできる。
関連オブジェクトを再取得してきてちゃんと値を合わせてやってもうまくいくんじゃないかな?(試してない
[csharp]
hoge.Piyo = null;
//これなら大丈夫。取得時にIncludeしてないのと同じ状態になる。
context.Hoge.Attach(hoge);
[/csharp]