我正在尝试了解有关Entity Framework 5和DbContext
的更多信息,我对实体代理有疑问。
给定生成的Alert
实体类:
public partial class Alert
{
public Alert()
{
this.Readings = new HashSet<Reading>();
}
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Reading> Readings { get; set; }
}
以下单元测试代码通过:
using (var context = new MyContext())
{
var alert = context.Alerts.Create();
// Entity is a proxy
Assert.AreNotSame(entity.GetType(), ObjectContext.GetObjectType(entity.GetType()));
// Related entity collections are just HashSet<T>
Assert.AreSame(typeof(HashSet<Reading>), alert.Readings.GetType());
// Attach entity to the context
context.Alerts.Attach(alert);
var entry = context.ChangeTracker.Entries<Alert>().Single();
// Initially it's unchanged
Assert.AreEqual(EntityState.Unchanged, entry.State);
// Change a property
alert.Title = "Changed title";
// However it's still unchanged
Assert.AreEqual(EntityState.Unchanged, entry.State);
}
我在网上四处寻找,试图找到生成代理对象实际做什么的确切解释。我有一些问题:
据我所知,关联属性getter / setter被覆盖。这里添加了什么逻辑?代理中还做了其他什么吗?
调试器显示_entityWrapper
类型为System.Data.Objects.Internal.EntityWrapperWithoutRelationships<System.Data.Entity.DynamicProxies.Alert_BF4E356370B8B5053A3384B5FAD30ECBA505359B71D47EBD90A674A9404D517C>
的字段。这是为了什么?
虚拟属性属性会做什么吗?
答案 0 :(得分:2)
来自answer by Rowan Miller in this MSDN question(强调我的):
如果您将所有属性设置为虚拟,那么EF将在运行时生成源自您的POCO分类的代理类,这些代理允许EF实时查找有关更改而不必捕获您保存对象的原始值,然后在保存时扫描更改(这显然具有性能和内存使用效益,但除非您将大量实体加载到内存中,否则差异可以忽略不计)。这些被称为“更改跟踪代理”。 如果您[仅]使您的导航属性变为虚拟,则仍会生成代理,但它更简单,并且只包含一些逻辑,以便在您访问导航属性时执行延迟加载。
答案 1 :(得分:1)
EF使用代理对象动态跟踪更改并使用延迟加载。当我们将属性定义为虚拟EF时,可以覆盖它以支持这些行为。
我们需要延迟加载才能在我们访问时加载导航属性
动态更改跟踪,如果我们对属性进行一些更改,代理会立即将更改跟踪通知。如果我们不使用动态更改跟踪,则更改跟踪器需要在保存更改之前浏览所有属性,以发现更改。
所以试试这个,
alert.Title = "Changed title";
context.DetectChanges();