这是一些演示我的问题的测试代码:
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 结束,但实际上它应该是未更改的。
如果我改为尝试使用附加,则会由于重复键而导致崩溃,因为两个查找实体最终出现在上下文中。
解决这个问题的最佳方法是什么?请注意,我已经相当简化了实际问题。在我的实际应用程序中,这是通过位于 EF DBContext 之上的几个不同的存储库层、工作单元和业务服务类来实现的。因此,我可以在 DBContext 中以某种方式应用的通用解决方案将是更可取的。