导航属性未在自引用关系中加载

时间:2015-04-11 11:56:24

标签: c# entity-framework

我的模型Category具有自引用关系:

public class Category
{
    public Category()
    {
        this.Childs = new HashSet<Category>();
    }

    public int CategoryId { get; set; }

    public int? ParentId { get; set; }
    public virtual Category Parent { get; set; }

    public HashSet<Category> Childs { get; set; }

    //... other useless properties
}

关系配置在上下文中定义:

modelBuilder.Entity<Category>()
            .HasOptional(c => c.Parent)
            .WithMany(c => c.Childs)
            .HasForeignKey(m => m.ParentId);

我还包括通用Repository,其中包含方法:

public IEnumerable<T> GetAll()
{
    return this.dbSet.ToList();
}

public IQueryable<T> AsQuerable()
{
    return this.dbSet.AsQueryable();
}

现在发生了非常奇怪的行为。我称之为方法:

var categoriesEntites =
        this.catogries.AsQuerable()
                      .Where(cat => cat.ProjectId == projectId 
                                    && cat.ParentId == null)
                      .ToList();
// this.categories is of type `Repository<Category>`

在结果中,Childs未加载..: Usual case

但是我之前打电话给GetAll

this.catogries.GetAll();
var categoriesEntites =
        this.catogries.AsQuerable()
                      .Where(cat => cat.ProjectId == projectId 
                                    && cat.ParentId == null)
                      .ToList();

突然导航属性有效.. With GetAll

之前我曾经多次使用这种方法,而且我从未遇到过这样的问题。 一些想法? LazyLoading当然已开启..

为了让事情变得更奇怪,我还有其他自引用实体(以完全相同的方式构建)并且没有这样的错误。

顺便说一句。对不起有关导航属性中的拼写错误,当然应该是Children,而不是Childs ...

1 个答案:

答案 0 :(得分:1)

当您在ToList()方法中执行GetAll()时,EF会加载整个表格并在本地存储这些实体。这就是执行此查询时它们似乎已加载的原因:

var categoriesEntites =
    this.catogries.AsQuerable()
                  .Where(cat => cat.ParentId == null)
                  .ToList();

如果查看上面查询生成的SQL,它实际上只获取ParentId为空的类别:

SELECT 
    [Extent1].[CategoryId] AS [CategoryId], 
    [Extent1].[ParentId] AS [ParentId]
    FROM [dbo].[Categories] AS [Extent1]
    WHERE [Extent1].[ParentId] IS NULL

即使在VS调试器中检查集合(触发延迟加载)之后,也不会获取子集合,因为它已经由EF本地加载和存储。

如果您想在不使用ToList()(或GetAll())的情况下获取子对象,请在您的子集合中使用virtual关键字。这是延迟加载的要求,将在代码或VS调试器访问该子集合时获取。

public virtual HashSet<Category> Childs { get; set; }