EF6 Code First Lazy Load导致空集合

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EF6 Code First Lazy Load导致空集合相关的知识,希望对你有一定的参考价值。

所以创建了动态代理,但我无法弄清楚我做错了什么来防止延迟加载导航属性。以下是我为测试该问题而运行的确切代码。

的DbContext:

public class MyDbContext : DbContext
{
    public MyDbContext()
        : base("MyConnection")
    {
    }

    public DbSet<One> Ones { get; set; }

    public DbSet<Many> Manies { get; set; }
}

类别:

public class One
{
    public int Id { get; set; }

    public virtual ICollection<Many> Manies { get; set; }

    public One()
    {
        Manies = new List<Many>();
    }
}

public class Many
{
    public int Id { get; set; }

    public string Value { get; set; }

    public int OneId { get; set; }

    public virtual One One { get; set; }

    public Many()
    {
    }
}

测试:

    [TestMethod]
    public void OneToManyTest()
    {
        One parent1 = new One();
        parent1.Manies.Add(new Many() { Value = "child 1" });
        parent1.Manies.Add(new Many() { Value = "child 2" });

        using (MyDbContext db = new MyDbContext())
        {
            db.Ones.Add(parent1);
            db.SaveChanges();
        }
        Assert.IsTrue(parent1.Id > 0, "Id not set");

        One parent2;
        using (MyDbContext db = new MyDbContext())
        {
            db.Configuration.ProxyCreationEnabled = true;
            db.Configuration.LazyLoadingEnabled = true;
            parent2 = db.Ones.Find(parent1.Id);//parent2 is a dynamic proxy
        }

        Assert.AreEqual(parent1.Id, parent2.Id);
        /*parent2.Manies is null*/
        Assert.AreEqual(parent1.Manies.Count, parent2.Manies.Count);//fails
    }

数据库:

我已经验证了正在插入数据库的正确信息。关系看起来很好。我确定我错过了一些明显的东西。

更新

这有效:

using (MyDbContext db = new MyDbContext())
{
    db.Configuration.ProxyCreationEnabled = true;
    db.Configuration.LazyLoadingEnabled = true;
    parent2 = db.Ones.Find(parent1.Id);//parent2 is a dynamic proxy
    Assert.AreEqual(parent1.Id, parent2.Id);
    Assert.AreEqual(parent1.Manies.Count, parent2.Manies.Count);
}

这不是:

using (MyDbContext db = new MyDbContext())
{
    db.Configuration.ProxyCreationEnabled = true;
    db.Configuration.LazyLoadingEnabled = true;
    parent2 = db.Ones.Find(parent1.Id);//parent2 is a dynamic proxy
}
using (MyDbContext db = new MyDbContext())
{
    Assert.AreEqual(parent1.Id, parent2.Id);
    Assert.AreEqual(parent1.Manies.Count, parent2.Manies.Count);//parent2.Manies is null
}

因此,内置延迟加载需要相同的db上下文。

答案

要触发延迟加载,您需要在处置上下文之前以某种方式访问​​该属性。

在离开上下文之前,您的测试代码不会访问该属性:

    One parent2;
    using (MyDbContext db = new MyDbContext())
    {
        db.Configuration.ProxyCreationEnabled = true;
        db.Configuration.LazyLoadingEnabled = true;
        parent2 = db.Ones.Find(parent1.Id);//parent2 is a dynamic proxy
    }
    // Context disposed: thsi would throw an exception:
    var manies = parent2.Manies.ToList()

此时,您的上下文已被处理掉。如果您尝试访问Manies属性,则会收到错误消息,说明这一点。

    One parent2;
    using (MyDbContext db = new MyDbContext())
    {
        db.Configuration.ProxyCreationEnabled = true;
        db.Configuration.LazyLoadingEnabled = true;
        parent2 = db.Ones.Find(parent1.Id);//parent2 is a dynamic proxy
        // Context available: this sill lazy load the Manies entities
        var manies = parent2.Manies.ToList(); 
    }

现在,如果您检查manies属性,它将可用。

延迟加载的想法是,虽然上下文可用,但是第一次访问最初未加载的属性时,它将在那时加载。

请参阅此文章,了解使用EF加载实体的不同方式(渴望,懒惰,明确):

Loading Related Entities

另一答案
parent2 = db.Ones.Include(o=>o.Manies).FirstOrDefault(o=>o.Id == parent1.Id);

以上是关于EF6 Code First Lazy Load导致空集合的主要内容,如果未能解决你的问题,请参考以下文章

MVC 5 的 EF6 Code First 入门

在 EF6 Code First 中支持表值函数吗?

MVC5与EF6 Code First 第一个入门完整实例教程

使用 EF6(和 Code First 迁移)针对不同的数据库系统

具有通用存储库和依赖注入和 SoC 的 EF6 Code First

EF6不支持sqlite Code First解决方案