これが私の問題をデモするいくつかのテストコードです:
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using NUnit.Framework;
namespace EFGraphInsertLookup
{
public class GraphLookup
{
public int ID { get; set; }
public string Code { get; set; }
}
public class GraphChild
{
public int ID { get; set; }
public virtual GraphRoot Root { get; set; }
public virtual GraphLookup Lookup { get; set; }
}
public class GraphRoot
{
public int ID { get; set; }
public virtual ICollection<GraphChild> Children { get; set; }
}
public class TestDbContext : DbContext
{
public DbSet<GraphRoot> GraphRoots { get; set; }
public DbSet<GraphChild> GraphChildren { get; set; }
public DbSet<GraphLookup> GraphLookups { get; set; }
public TestDbContext()
{
GraphLookups.ToList();
}
}
public class TestDbInit : DropCreateDatabaseAlways<TestDbContext>
{
protected override void Seed(TestDbContext context)
{
base.Seed(context);
context.GraphLookups.Add(new GraphLookup { Code = "Lookup" });
context.SaveChanges();
}
}
[TestFixture]
public class Tests
{
[Test]
public void MainTest()
{
Database.SetInitializer<TestDbContext>(new TestDbInit());
var lookupCtx = new TestDbContext();
var firstLookup = lookupCtx.GraphLookups.Where(l => l.Code == "Lookup").Single();
var graph = new GraphRoot
{
Children = new List<GraphChild> { new GraphChild { Lookup = firstLookup } }
};
var ctx = new TestDbContext();
ctx.GraphRoots.Add(graph); // Creates a new lookup record, which is not desired
//ctx.GraphRoots.Attach(graph); // Crashes due to dupe lookup IDs
ctx.SaveChanges();
ctx = new TestDbContext();
graph = ctx.GraphRoots.Single();
Assert.AreEqual(1, graph.Children.First().Lookup.ID, "New lookup ID was created...");
}
}
}
私の望みは、GraphLookupをルックアップテーブルとして機能させることです。この場合、レコードは他のレコードにリンクされますが、アプリケーションを介してレコードが作成されることはありません。
私が抱えている問題は、ルックアップエンティティが別のコンテキストで読み込まれる場合、たとえばキャッシュされている場合です。したがって、レコードの保存を行うコンテキストはそのエンティティを追跡していません。GraphRootDbSetでAddが呼び出されると、ルックアップはEntityStateがAddedになりますが、実際にはUnchangedである必要があります。
代わりにattachを使用しようとすると、2つのルックアップエンティティがコンテキストに含まれるため、キーが重複しているためにクラッシュが発生します。
これを解決するための最良の方法は何ですか?実際の問題をかなり単純化したことに注意してください。私の実際のアプリケーションでは、これは、EF DBContextの上にあるリポジトリ、作業単位、およびビジネスサービスクラスのいくつかの異なるレイヤーを通じて発生しています。したがって、DBContextに何らかの形で適用できる一般的なソリューションの方がはるかに望ましいでしょう。