0

次のエンティティがあります

public class Item
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Sections Sections { get; set; }
}

public class Section
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public class Sections : List<Section>, ICollection<Section>
{ }

アイテム ID 1 の新しいアイテムを追加しましたが、セクションがありません...

ここで、アイテムを変更して新しいセクションを追加したいと考えています。そのために、そのアイテムをコンテキストで取得し、別のコンテキストに保存しています。ここでは、ユーザーがいつオブジェクトを更新するかわからないため、2 つの別個のコンテキストを使用する必要があります。それまでコンテキストオブジェクトを開いたままにすることはできません。

        Item fAp;
        using (var ctx = new MyContext())
        {
            fAp = ctx.Items.Include(a => a.Sections).Single(a => a.Id == 1);
        }

        using (var ctx2 = new MyContext())
        {
            var nsec = new Section()
            {
                ID = 1,
                Name = "App Sec...1"
            };

            fAp.Sections.Add(nsec);
            ctx2.Entry(fAp).State = EntityState.Modified;
            ctx2.SaveChanges();
        }

これにより、新しいセクションがデータベースに追加されませんでした。次に、コードを修正し、ctx2.SaveChanges() を呼び出す前に次の行を追加しました。

            ctx2.Entry(nsec).State = EntityState.Added;

無事保存されました。

さて、私の問題は、非常に複雑なデータ階層があることです。つまり、Section クラスにも多くのサブ ナビゲーション プロパティがあり、それらのプロパティにもさらに多くのプロパティがあるということです。

そのようなすべてのプロパティを追跡し、それらの状態を手動で設定することは非常に困難です。この場合、どのようにデータを更新しますか?

もう 1 つ、熱心な読み込みは使用しません。つまり、Item オブジェクトの取得中に「Include」を使用しません。必要に応じて明示的な読み込みを使用し、最終的にオブジェクトを更新します。

最善の提案はありますか?

4

2 に答える 2

0

更新されたエンティティ

public class Item
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Sections Sections { get; set; }
    public OtherInfo Info { get; set; }
}
public class OtherInfo
{
    public Guid Id {get;set;}
    public string Description {get;set;}
}

Itemのオブジェクトを取得した後、ユーザーは何でも変更できます。上記の例を例にとると、ユーザーは新しいセクションを挿入し、オブジェクトItemを渡すことでcommitメソッドを呼び出します。

リポジトリクラスのCommitメソッド

public void Commit(Item fAp)
{
    using (var ct = new MyContext())
    {
        bool isExist = ct.Item.Any(a => a.Id == fAp.Id);
        if (!isExist)
        {
           ct.Items.Add(fAp);
        }
        else
        {
           ct.Items.Attach(fAp);
           ct.Entry(fAp).State = EntityState.Modified;
        }
        ct.SaveChanges();
    }
}

ここcommitメソッドでは、ユーザーがオブジェクトに対して何をしたかはわかりません。私のテストでは、セクションを追加してこのメ​​ソッドを呼び出しました。OtherInfoは変更されていないため、OtherInfoテーブルの主キーが重複しているというエラーがスローされます。

それで、それを機能させるために、私は次のようなすべてのエンティティのステータスを変更する必要があります

セクション-追加; OtherInfo-NoChange; アイテム-変更なし

構造が少し複雑なため、すべてのエンティティを追跡するのは難しいようです。

このアプローチ(コミット方法)は大丈夫ですか、それともより良い解決策を提案しますか?

于 2012-05-03T09:43:42.127 に答える
0

状態の設定は、呼び出しに渡した単一のエンティティのみに影響しEntryます。データの永続化のために新しいコンテキスト インスタンスを使用したら、保存するエンティティの EF 状態を常に通知する必要があります。

あなたの場合、次のいずれかを行う必要があります。

ctx2.Items.Attach(fAp); // Now you informed context about existing entity
fAp.Sections.Add(nsec); // Now you told both context and your item that new section exists

またはこれ(他の問題を回避するための推奨ソリューション):

fAp.Sections.Add(nsec); // Your item is not tracked by the new context yet
ctx2.Items.Add(fAp);     // Now context things that both item and section are new
ctx2.Entry(fAp).State = EntityState.Unchanged; // Make sure that item is not inserted again

またはこれ:

fAp.Sections.Add(nsec); // Your item is not tracked by the new context yet
ctx2.Items.Attach(fAp); // Now context things that both item and section are existing
ctx2.Entry(nsec).State = EntityState.Added; // Make sure that section is tracked as new 

そのようなすべてのプロパティを追跡し、それらの状態を手動で設定することは非常に困難です。この場合、どのようにデータを更新しますか?

コードはこれらの変更を行っているため、それほど難しくありません。すべてのエンティティのような追加のプロパティを追加IsDirtyし、それをヘルパーとして使用してエンティティの状態を追跡することもできます。

于 2012-05-02T12:37:34.513 に答える