一对多关系中奇怪的延迟加载

时间:2013-03-31 12:15:12

标签: c# .net entity-framework ef-code-first one-to-many

我遇到了一个奇怪的问题,我需要一些帮助。我试图在EF Code First中做一个简单的一对多关系。我们的想法是让一个 CardCategory 有多个 CardQuery 实例。

以下是我对CardCategory的定义:

public abstract class CardCategory
{
    [Key, DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
    public int Number { get; set; }

    [Required]
    public string Title { get; set; }

    [InverseProperty("Category")]
    public virtual ICollection<CardQuery> DataQueries { get; set; }

    public CardCategory()
    {
        // this ensures that the collection is never null (avoiding NullReferenceException).
        // it's no problem, because the constructor gets called before
        // data mapping occurs.
        DataQueries = new List<CardQuery>();
    }
}

这是CardQuery:

public abstract class CardQuery
{
    [Key, DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
    public int Number { get; set; }

    [InverseProperty("DataQueries")]
    public virtual CardCategory Category { get; set; }
}

奇怪的是,当我尝试使用我的数据样本(少数类别与少量查询相关联)时,只能单向运行。我可以像这样获取每个查询的父类:

var query = myContext.CardQueries.Find(1);
var category = query.Category; // this works alright

但是当我以相反的方式尝试这个时(为了获得一个类别的所有子查询),我得到的只是一个空集合

var category = myContext.CardCategories.Find(1);
var queries = category.DataQueries; // here is the problem, I get null or empty collection

也许你想知道CardCategory构造函数中的安全线是否与此有关。 它没有,相信我。我尝试的第一件事是删除它,我得到的只是一个空而不是空集合。

具有讽刺意味的是,“DataQueries”导航属性的工作原理不同:

var query = myContext.CardQueries.Find(1);
var category = query.Category;
var queries = category.DataQueries; // this works, I don't know what's different

看起来EF似乎无法填充属性,但我找不到原因。这在我之前从未发生过,我有点困惑。我很感激任何建议。

最后要清除的是,我的数据上下文配置如下:

LazyLoadingEnabled = true;
ProxyCreationEnabled = true;
AutoDetectChangesEnabled = true;

感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

我不建议使用Include,它会导致严重的性能下降。

你的问题是DataQueries是一个数组,只是调用category.DataQueries不会对存储执行任何查询(就像你不能编写myContext.CardQueries并自动获得结果一样)。您需要明确地调用启动器,例如ToList()或FirstOrDefault()。

所以,不要使用.Include尝试这个:

var category = myContext.CardCategories.Find(1);
var queries = category.DataQueries.ToList();

这将启动枚举器,您将获得DataQueries的结果。

作为旁注:你甚至可以通过例如过滤你的category.DataQueries。使用Where语句。

答案 1 :(得分:0)

尝试使用IQueryable<T>.Include()

var category = myContext.CardCategories
    .Include(e => e.DataQueries)
    .Find(1);

答案 2 :(得分:0)

我有一个类似但无关的问题。我试图延迟加载一些嵌套对象,例如访问Foo.Bar.Baz我的问题是Baz从未延迟加载,即使Bar on Bar是虚拟的。

事实证明,这个问题是由Bar私人所致。将ctor更改为protected允许EF正确创建Bar的代理类并启用延迟加载Baz集合。

相关问题