EF 5中的Eager Loading因深度图失败(使用.include())

时间:2013-05-23 18:17:50

标签: c# .net ef-code-first entity-framework-5 eager-loading

我首先使用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中的集合加载得很好。

我在这里错过了什么吗?

非常感谢所有的助手。

1 个答案:

答案 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个关键字以禁用延迟加载后进行了测试,但我得到了相同(成功)的结果。

我的测试截图:

Lots of Includes