![](/img/trans.png)
[英]EF Fluent Mapping not loading all children with eager loading using Include
[英]Eager Loading in EF 5 fails with deep graph (using .include())
我首先在EF 5中使用代碼。這是我的測試域
public class Master
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Query Query { get; set; }
}
public class Query
{
public Query()
{
ChildrenA = new HashSet<ChildA>();
ChildrenB = new HashSet<ChildB>();
}
public int Id { get; set; }
public string Name { get; set; }
public Master Master { get; set; }
public ChildB SpecialChild { get; set; }
public virtual ICollection<ChildA> ChildrenA { get; private set; }
public virtual ICollection<ChildB> ChildrenB { get; private set; }
public ChildB GetChildByName(string name)
{
return ChildrenB.Where(c => c.Name == name).FirstOrDefault();
}
}
public class ChildA
{
public int Id { get; set; }
public string Name { get; set; }
public int Query_Id { get; set; }
public virtual Query Query { get; set; }
}
public class ChildB
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Query SpecialQuery { get; set; }
public int Query_Id { get; set; }
public Query Query { get; set; }
}
這是我的上下文:
public class TestContext : DbContext
{
public TestContext()
:base()
{
}
public TestContext(string connectionString)
: base(connectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Master>()
.Property(m => m.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Master>()
.HasKey(m => m.Id);
modelBuilder.Entity<Query>()
.Property(q => q.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Query>()
.HasKey(q => q.Id);
modelBuilder.Entity<Query>()
.HasOptional(q => q.Master)
.WithOptionalPrincipal(m => m.Query);
modelBuilder.Entity<Query>()
.HasOptional(q => q.SpecialChild)
.WithOptionalPrincipal(c => c.SpecialQuery);
modelBuilder.Entity<ChildA>()
.Property(c => c.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<ChildA>()
.HasKey(c => new { c.Query_Id, c.Id });
modelBuilder.Entity<ChildA>()
.HasRequired(c => c.Query)
.WithMany(q => q.ChildrenA)
.HasForeignKey(c => c.Query_Id);
modelBuilder.Entity<ChildB>()
.Property(c => c.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<ChildB>()
.HasKey(c => new { c.Query_Id, c.Id});
modelBuilder.Entity<ChildB>()
.HasRequired(c => c.Query)
.WithMany(m => m.ChildrenB)
.HasForeignKey(c => c.Query_Id);
}
public DbSet<Master> Masters { get; set; }
public DbSet<ChildA> ChildrenA { get; set; }
public DbSet<ChildB> ChildrenB { get; set; }
}
注意:當從POCO類的集合中刪除對象時,復合PK允許EF強制實體刪除。
這是一些加載測試數據的代碼:
System.Data.Entity.Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
string connectionString = string.Format("Data Source={0};", SQLCEFileName());
using (TestContext context = new TestContext(connectionString))
{
Master master = new Master() { Name = "Master1", Query = new Query() { Name = "Query1" } };
master.Query.ChildrenA.Add(new ChildA() { Name = "ChildA1" });
master.Query.ChildrenB.Add(new ChildB() { Name = "ChildB1" });
master.Query.ChildrenB.Add(new ChildB() { Name = "ChildB2" });
master.Query.ChildrenB.Add(new ChildB() { Name = "ChildB3" });
master.Query.ChildrenB.Add(new ChildB() { Name = "ChildB4" });
context.Masters.Add(master);
Query special = new Query() { Name = "Special" };
ChildB c3 = master.Query.GetChildByName("ChildB3");
c3.SpecialQuery = special;
special.ChildrenA.Add(new ChildA() { Name = "SpecialChildA1" });
special.ChildrenB.Add(new ChildB() { Name = "SpecialChildB1" });
special.ChildrenB.Add(new ChildB() { Name = "SpecialChildB2" });
special.ChildrenB.Add(new ChildB() { Name = "SpecialChildB3" });
special.ChildrenB.Add(new ChildB() { Name = "SpecialChildB4" });
context.SaveChanges();
}
現在,您將看到從ChildB到Query的可選關系。 因此,ChildB可以有一個查詢,然后可以擁有自己的ChildA和ChildB列表。 在實踐中,它是如此深入。
當我查詢Master並通過在查詢的最低級別(Master.Query.ChildrenB.SpecialQuery.Children [A或B])上使用include()來強制進行快速加載時,則僅加載一個集合(ChildrenA或ChildrenB)。
這是一個示例查詢,該查詢應強制加載整個圖形:
using (TestContext context = new TestContext(connectionString))
{
Master master = context.Masters
.Where(m => m.Name == "Master1")
.Include("Query.ChildrenA")
.Include("Query.ChildrenB.SpecialQuery.ChildrenA")
.Include("Query.ChildrenB.SpecialQuery.ChildrenB")
.FirstOrDefault();
ChildB c = master.Query.GetChildByName("Child3");
}
注意:我知道下面的集合中引用實體的語法是錯誤的,我只是用它來說明問題。
此時master.Query.ChildrenB [2] .SpecialQuery.ChildrenA.Count為1(正確)master.Query.ChildrenB [2] .SpecialQuery.ChildrenB.Count為0(應為4)
如果我修改查詢並刪除.Include(“ Query.ChildrenB.SpecialQuery.ChildrenA”),則master.Query.ChildrenB [2] .SpecialQuery.ChildrenB.Count是預期的4。
這真的很奇怪,因為master.Query.ChildrenA和master.Query.ChildrenB中的集合加載得很好。
我在這里想念什么嗎?
非常感謝所有助手。
我沒有任何解釋,只是使用SQL Server 2008 R2 Express在VS 2010中的.NET 4.0上對EF 5.0進行了測試。 我已經復制並粘貼了您的代碼,但是刪除了顯式連接字符串,因為顯然您正在使用SQL Server CE 4.0。
對我來說,它按預期工作,這就提出了一個問題,即SQL Server CE提供程序是否在此處存在錯誤。
我唯一的區別是,有問題的ChildB(我認為是"ChildB3"
)在我的集合中具有索引3,而不像在測試中那樣具有索引2。 在刪除所有virtual
關鍵字以禁用延遲加載后,我也進行了測試,但結果相同(成功)。
我的測試截圖:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.