我首先使用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; }
}
注意:复合PK是允许EF在POCO类中从集合中删除对象时强制删除实体。
以下是一些加载测试数据的代码:
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可以拥有一个Query,然后可以拥有它自己的ChildA和ChildB列表。在实践中,它就像它一样深。
当我在查询的最低级别(Master.Query.ChildrenB.SpecialQuery.Children [A或B])上使用include()查询Master并强制执行Eager Loading时,只有一个集合(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中的集合加载得很好。
我在这里错过了什么吗?
非常感谢所有的助手。
答案 0 :(得分:1)
我没有解释,只是使用 SQL Server 2008 R2 Express 在VS 2010中使用.NET 5.0上的EF 5.0进行了测试。我复制并粘贴了你的代码,除了我删除了显式连接字符串,因为显然你使用的是SQL Server CE 4.0。
对我而言,它可以正常运行,如果SQL Server CE提供程序在此处存在错误,则会引发问题。
我唯一的区别是有问题的ChildB(我认为"ChildB3"
)在我的集合中有索引3,而不是在你的测试中有索引2。我还在删除所有virtual
个关键字以禁用延迟加载后进行了测试,但我得到了相同(成功)的结果。
我的测试截图: