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

Why are collection navigation properties not initialized for lazy loading proxy classes

在我的一个项目中,我在实体上使用带有虚拟导航属性的实体框架。这意味着实体是从数据库加载的,或者是用IDbSet.Create()创建的,会返回一个dynamicProxy。因为我只将导航属性设置为虚拟的,所以该代理执行延迟加载和无更改跟踪(所有属性都需要是virtual才能获得更改跟踪代理)。

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

然后,我尝试将所有属性都设置为virtual,这样我就得到了一个带有更改跟踪的dynamicProxy,令我惊讶的是,这些导航属性都已初始化。

请参见以下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
2
3
4
public LazyLoading()
{
   Posts = new List();
}

我认为最好使用一个支持字段——这与在某些情况下不被调用的匿名构造函数有关(序列化或其他——为含糊不清道歉)。所以我这样做:

1
2
3
4
5
6
7
8
9
10
11
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;
    }
}

很遗憾,我无法解释为什么当您将所有属性标记为"虚拟"时,不会出现错误…