为什么没有为延迟加载代理类初始化集合导航属性

时间:2014-06-05 11:18:26

标签: c# .net entity-framework ef-code-first poco

在我的一个项目中,我使用Entity Framework和实体上的虚拟导航属性。这意味着实体从数据库加载或使用IDbSet<T>.Create()创建,返回DynamicProxy。因为我只将导航属性设置为虚拟,所以此代理会进行延迟加载而不进行更改跟踪(所有属性都需要virtual才能获得更改跟踪代理)。

我的假设是DynamicProxy负责初始化虚拟ICollection<T>属性,就像从数据库加载实体时一样。但是当我使用IDbSet<T>.Create()创建新实体时,这些导航属性仍为null

然后我尝试制作所有属性virtual,因此我获得了一个带有更改跟踪的DynamicProxy,令我惊讶的是这些导航属性已初始化。

请参阅以下示例:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;

static class Program
{
    static void Main()
    {
        using (var db = new BloggingContext())
        {
            var changeTrackingBlog = db.ChangeTrackingBlogs
                                       .Create(); // returns a DynamicProxy
            var changeTrackingBlogPostCount = changeTrackingBlog
                              .Posts
                              .Count; // Posts has type EntityCollection<Post>

            var lazyLoadingBlog = db.LazyLoadingBlogs
                                    .Create(); // returns a DynamicProxy
            var lazyLoadingBlogPostCount = lazyLoadingBlog.Posts
                                                .Count; // Posts == null
        } 
    }
}

public class BloggingContext : DbContext
{
    public IDbSet<Post> Posts { get; set; }
    public IDbSet<ChangeTrackingBlog> ChangeTrackingBlogs { get; set; }
    public IDbSet<LazyLoadingBlog> LazyLoadingBlogs { get; set; }
}

public class Post
{
    [Key]
    public int PostId { get; set; }

    public virtual ChangeTrackingBlog ChangeTrackingBlog { get; set; }
    public virtual LazyLoadingBlog LazyLoadingBlog { get; set; }
}

public class ChangeTrackingBlog
{
    [Key]
    public virtual int BlogId { get; set; }

    public virtual ICollection<Post> Posts { get; set; }
}

public class LazyLoadingBlog
{
    // Not all properties are virtual, so no Change tracking, just lazy loading
    [Key]
    public int BlogId { get; set; } 

    public virtual ICollection<Post> Posts { get; set; }
}

我希望有人能解释这里发生的事情。

1 个答案:

答案 0 :(得分:2)

避免空引用的常用方法是在构造函数中初始化集合:

public LazyLoading()
{
   Posts = new List();
}

我认为使用支持字段可能是更好的做法 - 与在某些情况下不被调用的匿名构造函数(序列化或某些东西 - 模糊的道歉)有关。所以我这样做:

public class LazyLoadingBlog
{
    private ICollection<Post> _Posts = new List<Post>();

    public virtual ICollection<Post> Posts 
    { 
       get { return _Posts ; }
       //protected set lets EF override for lazy loading
       protected set { _Posts = value; 
    }
} 

不幸的是,当你将所有属性标记为虚拟时,我无法解释为什么你没有收到错误...