【发布时间】:2014-07-26 08:46:45
【问题描述】:
在我的一个项目中,我使用实体框架和实体上的虚拟导航属性。这意味着实体是从数据库中加载或使用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; }
}
我希望有人能解释这里发生了什么。
【问题讨论】:
-
当您将所有属性设为虚拟时,您是否确定这些集合导航属性已初始化,从而允许创建更改跟踪代理?我认为你错了。这些集合属性仅在您使用延迟加载时自动实例化并访问它们。如果不是,它们仍然为空。
-
@JotaBe:好点,但
Posts属性在更改跟踪代理的情况下被访问之前被初始化。 -
这就是我的意思:总是初始化集合属性,除非你通过延迟加载来加载它,否则你会得到一个“空引用异常”。除非它们是惰性的、急切的或显式加载的,否则永远不会初始化 AFAIK 集合属性。把它放在你的类构造函数中不会产生任何干扰。
标签: c# .net entity-framework ef-code-first poco