27

この特定のエラー メッセージに関連するいくつかの質問/回答を読みましたが、適切な解決策がよくわかりません。

EF4 コンテキストを作成し、使用してから破棄する必要があることを何度も読みました。アプリケーション全体で、さまざまなコンテキスト オブジェクトを使用してあちこちにエンティティを読み込んでおり、最終的にエンティティを関連付けたいと考えています。

簡単にエラーを引き起こす単純なコンソール アプリケーションを作成しました。非常に単純なモデルを図で示し、その後にコードを示します。

2 つの異なるエンティティが同じコンテキストを共有するようにするにはどうすればよいですか? 新しいコンテキストを作成し、2 つのエンティティを (すでに持っているにもかかわらず) 再度ロードして、単にそれらを関連付けて保存する必要がありますか?

既存の適切な質問/回答を単に見逃した場合は、適切な場所を教えてください。

シンプルな EF4 モデル図

internal class Program {

    private static void Main(string[] args) {
        DeleteAllEntities();
        CreateInitialEntities();
        Owner o = LoadOwner();
        Child c = LoadChild();
        AssociateAndSave(o, c);
    }

    private static void AssociateAndSave(Owner o, Child c) {
        using (var context = new ModelEntities()) {
            // Exception occurs on the following line.
            o.Children.Add(c);
            context.Attach(o);
            context.SaveChanges();
        }
    }

    private static Owner LoadOwner() {
        using (var context = new ModelEntities()) {
            return ((from o in context.Owners
                     select o).First());
        }
    }

    private static Child LoadChild() {
        using (var context = new ModelEntities()) {
            return ((from c in context.Children
                     select c).First());
        }
    }

    private static void CreateInitialEntities() {
        using (var context = new ModelEntities()) {
            Owner owner = new Owner();
            Child child = new Child();
            context.Owners.AddObject(owner);
            context.Children.AddObject(child);
            context.SaveChanges();
        }
    }

    private static void DeleteAllEntities() {
        using (var context = new ModelEntities()) {
            List<Child> children = (from c in context.Children
                                    select c).ToList();
            foreach (var c in children)
                context.Children.DeleteObject(c);
            List<Owner> owners = (from o in context.Owners
                                  select o).ToList();
            foreach (var o in owners)
                context.Owners.DeleteObject(o);
            context.SaveChanges();
        }
    }
}
4

2 に答える 2

22

同じコンテキストで子オブジェクトと所有者オブジェクトへの参照を取得する必要があります。これに対するアプローチは、ID を取得し、それらをパラメーターとしてAssociateAndSave(int oId, int cId)メソッドに渡すことです。

次に、同じコンテキストでオブジェクトへの参照を取得し、添付ファイルを作成します。

private static void Main(string[] args)
{
    DeleteAllEntities();
    CreateInitialEntities();
    int oId = LoadOwnerId();
    int cId = LoadChildId();
    AssociateAndSave(oId, cId);
}

private static int LoadOwnerId()
{
    using (var context = new ModelEntities())
    {
        return (from o in context.Owners
                select o).First().Id;
    }
}

private static int LoadChildId()
{
    using (var context = new ModelEntities())
    {
        return (from c in context.Children
                select c).First().Id;
    }
}

private static void AssociateAndSave(int oId, int cId)
{
    using (var context = new ModelEntities())
    {
        var owner = (from o in context.Owners
                        select o).FirstOrDefault(o => o.ID == oId);
        var child = (from o in context.Children
                        select o).FirstOrDefault(c => c.ID == cId);

        owner.Children.Add(child);
        context.Attach(owner);
        context.SaveChanges();
    }
}
于 2013-03-07T15:09:23.683 に答える
4

各コンテキストはそのオブジェクトを個別に追跡するため、別のコンテキストのインスタンスを使用して、あるコンテキストからオブジェクトを削除することはできません。

1 つのアイデアは、操作が同じコンテキスト内で行われるように、各メソッドにコンテキスト タイプのパラメーターを提供することです。

元:

private static void CrudOperationExample(DBContext contextInstane)
{
    //perform crud operations.
}

ORM で非常に役立つので、依存性注入を探すことをお勧めします。

于 2013-03-07T15:09:00.360 に答える