EF:加载相关实体懒惰的方式不起作用

时间:2015-02-04 13:21:46

标签: c# .net entity-framework

我哪里错了?我在导航属性NullReferenceExeption中收到Events。它被标记为virtual,并且LazyLoadingEnabled被明确允许。

程序代码:

using (var db = new Db())
{
    var person = new Person();
    person.Name = "bla bla";
    db.Persons.Add(person);
    person.Events = new List<Event>(1);
    person.Events.Add(new Event() { Description = "ABC", At = DateTime.Now });
    db.SaveChanges();
}

using (var db = new Db())
{
    var person = db.Persons.First();

    Console.WriteLine(person.Events == null);  //Output: True
    Console.WriteLine(person.Events.Count);    //System.NullReferenceException
}

显式加载:

var person = db.Persons.First();
db.Entry(person).Collection(p => p.Events).Load();
Console.WriteLine(person.Events == null);  //Output: False
Console.WriteLine(person.Events.Count);    //1

类结构:

class Db : DbContext
{
    public Db()
    {
        Database.SetInitializer(new DropCreateDatabaseAlways<Db>());
        Configuration.LazyLoadingEnabled = true;
    }

    public DbSet<Person> Persons { get; set; }
    public DbSet<Event> Events { get; set; }
}

class Person
{
    public int id { get; set; }
    public string Name { get; set; }

    public virtual List<Event> Events { get; set; }
}

class Event
{
    public int id { get; set; }
    public DateTime At { get; set; }
    public string Description { get; set; }

    public Person Person { get; set; }
    public int PersonId { get; set; }
}

5 个答案:

答案 0 :(得分:2)

您的模型类需要公开才能延迟加载。将class Personclass Event更改为public class Person等,您的测试计划将开始有效。

答案 1 :(得分:-1)

很简单。

在Person类和init Events集合中创建默认构造函数,如

public Person()
{
   Events = new HashSet<Event>();
}

并将类型为Person的虚拟属性添加到Event类

编辑: 在EF codefirst中,您负责集合初始化,EF负责从数据库中填充此集合

答案 2 :(得分:-1)

new Person()替换为context.Persons.Create()

这将为您提供实体框架人员代理,而不是Person。此代理类派生自Person,但其Events属性被Lazy加载逻辑覆盖。

然而,这并没有消除代码中的主要问题。哪个是Context的重用。你不应该这样做。

答案 3 :(得分:-1)

您的代码没有任何问题:如果您对空集合执行Count,您将始终获得NullReferenceException - 这与Entity Framework无关,那个.NET。

null集合和空集合之间存在差异。

现在,如果您想避免此类NullReferenceException例外,您始终可以在默认构造函数中启动列表,如:

class Person
{
    public Person()
    {
        Events = new List<Event>();
    }

    public int id { get; set; }
    public string Name { get; set; }

    public virtual List<Event> Events { get; set; }
}

答案 4 :(得分:-1)

public class Person
{
    public Person()
    {
          Events = new List<Event>();
    }

    public int id { get; set; }
    public string Name { get; set; }

    public virtual List<Event> Events { get; set; }
}

public class Event
{    
    public int id { get; set; }
    public DateTime At { get; set; }
    public string Description { get; set; }

    public Person Person { get; set; }
    public int PersonId { get; set; }
}

您需要使用相同类型的集合和NOT&#39; HashSet#39;来初始化任何Collection导航属性,如下所示。