web-dev-qa-db-ja.com

Entity Framework 4-AddObjectとAttach

私は最近Entity Framework 4を使用していますが、 ObjectSet.Attach および ObjectSet.AddObject を使用するタイミングについて少し混乱しています。

私の理解から:

  • エンティティがシステムに既に存在する場合、「アタッチ」を使用します
  • 新しいエンティティを作成するときに「AddObject」を使用します

新しい人を作成するの場合、これを行います。

var ctx = new MyEntities();
var newPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.AddObject(newPerson);
ctx.SaveChanges();

既存の個人を変更するの場合、これを行います。

var ctx = new MyEntities();
var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
existingPerson.Name = "Joe Briggs";
ctx.SaveChanges();

これは非常に単純なの例であることに留意してください。実際には、Pure POCO(コード生成なし)、Repositoryパターン(ctx.Personsを処理しない)、およびUnit of Work(ctx.SaveChangesを処理しない)を使用しています。しかし、「隠れて」、上記は私の実装で起こることです。

今、私の質問-私はまだAttachを使用しなければならないシナリオを見つけていません。

ここで何が欠けていますか? Attachを使用する必要があるのはいつですか?

編集

明確にするために、AddObject over(またはその逆)を使用する場合のexamplesを探しています。

編集2

以下の答えは正しいです(私は受け入れました)が、アタッチが役立つ別の例を追加すると思いました。

既存のPersonの変更の上記の例では、2つのクエリが実際に実行されています。

1つはPersonを取得し(.SingleOrDefault)、もう1つはUPDATEを実行します(.SaveChanges)。

(何らかの理由で)システムに「Joe Bloggs」が存在することを既に知っていた場合、なぜ彼を最初に取得するために追加のクエリを行うのですか?私はこれを行うことができます:

var ctx = new MyEntities();
var existingPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.Attach(existingPerson);
ctx.SaveChanges();

これにより、UPDATEステートメントのみが実行されます。

127
RPM1984

ObjectContext.AddObject andObjectSet.AddObject
AddObjectメソッドは、notを行う新しく作成されたオブジェクトを追加するためのものですデータベースに存在します。エンティティは、自動的に生成された一時的なEntityKeyを取得し、そのEntityStateはAddedに設定されます。 SaveChangesが呼び出されると、このエンティティをデータベースに挿入する必要があることがEFに明確になります。

ObjectContext.Attachおよび ObjectSet.Attach
一方、Attachは既にexistデータベース内。 EntityStateをAddedに設定するのではなく、AttachはUnchangedEntityStateになります。これは、コンテキストに接続されてから変更されていないことを意味します。接続しているオブジェクトは、データベースに存在すると想定されます。オブジェクトをアタッチした後に変更した場合、SaveChangesを呼び出すと、EntityKeyの値を使用して、dbテーブルで一致するIDを見つけて適切な行を更新(または削除)します。

さらに、Attachメソッドを使用すると、ObjectContextに既に存在するがnot自動的に接続されました。基本的にAttachの主な目的は、既にObjectContextにアタッチされており、not新規のエンティティを接続することです。したがって、Attachを使用して、EntityStateが追加されたエンティティをアタッチすることはできません。この場合、Add()を使用する必要があります。

たとえば、Personエンティティには、AddressエンティティのコレクションであるAddressesという名前のナビゲーションプロパティがあるとします。コンテキストから両方のオブジェクトを読み取ったが、それらは互いに関連していないため、そのようにしたいとしましょう:

var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
var myAddress = ctx.Addresses.First(a => a.PersonID != existingPerson.PersonID);
existingPerson.Addresses.Attach(myAddress);
// OR:
myAddress.PersonReference.Attach(existingPerson)
ctx.SaveChanges();
158
Morteza Manavi

これは遅い応答ですが、これを見つける他の人を助けるかもしれません。

基本的に、「切断」エンティティは、「使用」スコープ外のエンティティを操作すると発生する可能性があります。

Employee e = null;

using (var ctx = new MyModelContainer())
{
     e = ctx.Employees.SingleOrDefault(emp => emp .....);
}

using (var ctx2 = new MyModelContainer())
{
     e; // This entity instance is disconnected from ctx2
}

別の「using」スコープを入力すると、「e」変数は以前の「using」スコープに属し、以前の「using」スコープが破棄されるため「e」が切断されるため、切断されます。

それは私がそれを理解する方法です。

28
TchiYuan

これは Programming Entity Framework:DbContext からの引用です

コンテキストで追跡されていないエンティティでRemoveを呼び出すと、InvalidOperationExceptionがスローされます。 Entity Frameworkはこの例外をスローします。これは、削除しようとしているエンティティが、削除のマークを付ける必要がある既存のエンティティであるか、無視するだけの新しいエンティティであるかが明確でないためです。このため、Removeだけを使用して、切断されたエンティティをDeletedとしてマークすることはできません。最初に添付する必要があります

private static void TestDeleteDestination()
{
    Destination canyon;
    using (var context = new BreakAwayContext())
    {
        canyon = (from d in context.Destinations
        where d.Name == "Grand Canyon"
        select d).Single();
    }
    DeleteDestination(canyon);
}
private static void DeleteDestination(Destination destination)
{
    using (var context = new BreakAwayContext())
    {
        context.Destinations.Attach(destination);
        context.Destinations.Remove(destination);
        context.SaveChanges();
    }
}

TestDeleteDestinationメソッドは、クライアントアプリケーションがサーバーから既存のDestinationを取得し、サーバー上のDeleteDestinationメソッドに渡すことをシミュレートします。 DeleteDestinationメソッドは、Attachメソッドを使用して、既存の宛先であることをコンテキストに通知します。次に、Removeメソッドを使用して、削除する既存の宛先を登録します

7
Teoman shipahi