这是一些演示我问题的测试代码:
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作为一个查找表,其中记录与其他记录链接,但从应用程序中永远不会创建记录。
我遇到的问题是,在不同的上下文中加载查找实体时(例如在缓存中),当执行记录的保存操作时,上下文无法跟踪该实体,并且当调用GraphRoot DbSet的Add方法时,查找结果会被添加到EntityState中,但实际上它应该是未更改的。
如果我尝试使用attach,由于两个查找实体最终进入上下文,因此会导致重复键而崩溃。
有什么解决方法吗?请注意,我已经大大简化了实际的问题。在我的实际应用程序中,这发生在EF DBContext的多个不同层的存储库、工作单元和业务服务类之间。因此,最好能够应用于DBContext中的通用解决方案。