這裏原來加載的一些測試代碼演示我的問題:實體框架 - 避免「查找」實體獲取添加狀態時,在另一種情況下
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中以某種方式應用一個通用的解決方案,這將是非常受歡迎的。
這很有道理,奧利。我希望找到一些可以在添加之後修改狀態的位置,但在SaveChanges之前。這樣消費者代碼就不會改變。另外,緩存並不是我遇到這個問題的唯一時間。當用戶界面加載查找時,也可能會發生這種情況,比如稱爲下拉菜單,然後將這些查找加入到添加中。 – RationalGeek
@RationalGeek - 對。可能沒有解決這個問題的「靈丹妙藥」。這是EF無法解決你想要做的事情的情況;這是一個最好的猜測。 – Olly
@RationalGeek - 概念上,如果您有類似於內部使用EF上下文的存儲庫的內容,呼叫者不必擔心遵守某些規則以避免EF錯誤。因此,使用EF的代碼必須負責適當地設置實體狀態。只有它能夠知道什麼是「參考」數據和什麼是「交易」數據。前者需要將其狀態設置爲未更改(或完全分離)。我喜歡將「參考」數據加載到高級環境中的想法,因此它永遠不會被標記爲添加。 – Olly