说好为大家带来一系列的文章,现在就写第二篇。开始之前,再啰嗦两句,EF4.1 RTW版本已经发布:http://www.microsoft.com/downloads/en/details.aspx?FamilyID=b41c728e-9b4f-4331-a1a8-537d16c6acdf&displaylang=en。第一篇有关DbSet.Find的文章,请看:http://www.cnblogs.com/LingzhiSun/archive/2011/03/22/EF41_Find.html。
今天为大家带来DbSet.Local属性的使用与实现。和上次介绍的Find函数首先查找context中缓存的实体类似,DbSet的Local属性也是返回context中缓存并且被跟踪的实体。不同点在于,Local属性不会返回状态为EntityState.Deleted的实体,且即使缓存中什么实体都没有,也不会对数据库进行访问。这样的设计也正符合Local(本地)之意。
看一个例子:
using (var db = new MyDbContext())
{
// 此处调用EF4.1的新扩展方法DbSet<>.Load()从数据库导入对应的实体到缓存中
db.People.Load();
db.People.Add(new Person { Name = "Michael" });
db.People.Remove(db.People.Find(1));
foreach (var p in db.People.Local)
{
// 这里调用了EF4.1的新方法Entry来得到实体的DbEntryEntry
Console.WriteLine("Found {0}: {1} with state {2}", p.PersonID, p.Name, db.Entry(p).State);
}
}
这里的输出结果类似于:
Found 0: Michael with state Added
Found 2: Jennie with state Unchanged
Found 3: Bob with state Unchanged
Found 4: Mike with state Unchanged
...
PersonID为1的实体不会出现在这里,因为此时它的状态是Deleted。而姓名为Michael的实体因为是新增的实体,其主键还没有在数据库端生成,所以其PersonID为0。
Local属性为什么这么设计呢?照理说状态为Deleted的实体同样应该是本地缓存的啊!读者可能会发现,Local属性返回的数据类型是ObservableCollection<T>。我们知道ObservableCollection<T>常被用于WPF数据绑定。其实Local属性的设计也是为了方便大家做数据绑定的。试想在数据绑定时,如果被我们删除的实体仍然出现在Local属性的集合中,UI控件则会仍然显示这些已被我们标记为Deleted的实体。反之对于新增的实体(但还没有将更新提交到数据库),我们当然希望在做数据绑定时,UI控件也能显示它们的信息。再为大家介绍一些背景知识:过去我们如果直接把控件绑定到EF的ObjectSet<T>集合上,如果我们删除某些实体(并未提交数据库),UI控件会有相应的反应(也删除实体)。但是当我们调用类似AddObject方法在ObjectSet<T>里新增实体时,UI控件并不会有任何变化(新增实体不出现在控件)。个人觉得这是之前EF设计上的一些缺陷。有关更详细的讨论,请参阅这个MSDN帖子,http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/8ac0f9a9-00e0-431a-9e7a-cb31dde83828。
有关Local属性的用法以及如何使用Local属性来做WPF和Winform数据绑定,可以参阅这三篇ADO.NET产品组的博文:(如果大家需要,我也可以对这些博文做翻译工作或者写一些有关EF数据绑定的文章)
http://blogs.msdn.com/b/adonet/archive/2011/03/08/ef-feature-ctp5-code-first-model-with-master-detail-wpf-application.aspx
下面我们一起来分析下Local属性的实现。
由于没有EF4.1的源码,所以仍然使用.NET Reflector。 DbSet<>.Local属性是只读的。其get方法调用EF内部封装的InternalSet<T>.Local属性(同样只读)。这里和上次介绍的DbSet<>.Find函数一样,先调用DetectChanges函数来同步POCO实体的状态。(有关DetectChanges函数,详见MSDN文档Working with POCO Entities )
public ObservableCollection<TEntity> Local
{
get
{
this.InternalContext.DetectChanges(false);
if (this._localView == null)
{
DbLocalView<TEntity> view1 = this._localView;
}
return (this._localView = new DbLocalView<TEntity>(this.InternalContext));
}
}
这里判断_localView对象是否为NULL,但这里的逻辑我也不是很明白。在咨询了产品组之后发现,这是Reflector 6.5的分析IL时的一个问题。正确的代码应该是使用了类似于C# ??的运算符来判断_localView对象是否为NULL。如果为NULL则生成一个DbLocalView<TEntity>的对象并返回。
public ObservableCollection<TEntity> Local
{
get
{
this.InternalContext.DetectChanges(false);
return this._localView ?? (this._localView = new DbLocalView<TEntity>(this.InternalContext));
}
}
下面看看DbLocalView<TEntity>类的构造函数:
public DbLocalView(InternalContext internalContext)
{
this._internalContext = internalContext;
try
{
this._inStateManagerChanged = true;
foreach (TEntity local in this._internalContext.GetLocalEntities<TEntity>())
{
base.Add(local);
}
}
finally
{
this._inStateManagerChanged = false;
}
this._internalContext.RegisterObjectStateManagerChangedEvent(new CollectionChangeEventHandler(this.StateManagerChangedHandler));
}
这里两个比较关键的函数是GetLocalEntities和RegisterObjectStateManagerChangedEvent。前者是调用了ObjectStateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Added | EntityState.Unchanged)以得到状态为Modified、Added和Unchanged的实体对象。而后者则是Local属性实现数据绑定功能的关键,将StateManagerChangedHandler这个事件处理函数赋给ObjectStateManager.ObjectStateManagerChanged事件。该事件是当任何实体被添加或从ObjectStateManager中删除时都会被激发的。
StateManagerChangedHandler函数其实就是在ObjectStateManagerChanged事件被激发时,调用对应的ObservableCollection<T>.Remove或ObservableCollection<T>.Add操作。这样也就将ObservableCollection<T>和EF缓存的实体联系了起来,简单的数据绑定便实现了。
private void StateManagerChangedHandler(object sender, CollectionChangeEventArgs e)
{
try
{
this._inStateManagerChanged = true;
TEntity element = e.Element as TEntity;
if (element != null)
{
if ((e.Action == CollectionChangeAction.Remove) && base.Contains(element))
{
base.Remove(element);
}
else if ((e.Action == CollectionChangeAction.Add) && !base.Contains(element))
{
base.Add(element);
}
}
}
finally
{
this._inStateManagerChanged = false;
}
}
再次一口气写完。希望对您学习EF有所帮助吧!
分享到:
相关推荐
EntityFramework 4.1独立安装包
本书是关于Entity framework code first 的详细介绍,在本书中,你可以学到从无到有的创建基于Entity framework code first的项目
官方网下载的EntityFramework4.1 安装包,本人vs2010版在用
entityframework 4.1教程
EF 4.1有哪些新玩新儿? 1. 首先当然是DbContext API,它是基于以前版本中的ObjectContext和其他一些类型抽象出的一个简单的API,针对常用开发场景和编程模式进行了优化。DbContext可以被于Database First, Model...
Entity Framework 4.1Entity Framework 4.1Entity Framework 4.1Entity Framework 4.1Entity Framework 4.1Entity Framework 4.1
Programming Entity Framework: DbContext Querying, Changing, and Validating Your Data with Entity Framework By Julia Lerman, Rowan Miller
Packt.Entity.Framework.4.1.Expert's.Cookbook.2012
清晰版 Programming Entity Framework_DbContext
由于网上没有很详细的介绍 Entity Framework 4.1对 Sqlite 的操作,本人就简单写一个例子给入门的朋友 增删改查全有了,而且代码用简单分层写,对入门的朋友有帮助
微软正版图书:Getting Started with the Entity Framework 4.1 using ASP.NET MVC 微软正版图书:Getting Started with the Entity Framework 4.1 using ASP.NET MVC 微软正版图书:Getting Started with the ...
ADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (O/R Mapping) 解决方案,该插件为4.1版本
想学Entity.Framework.DbContext吗?想学单元测试吗?想知道Entity.Framework如何实现Unit Of Work,Reposit模式吗?这本书应有尽有.
[奥莱理] Programming Entity Framework DbContext (英文版) [奥莱理] Programming Entity Framework DbContext (E-Book) ☆ 出版信息:☆ [作者信息] Julia Lerman, Rowan Miller [出版机构] 奥莱理 [出版日期...
[Packt Publishing] Entity Framework 4.1 Expert's Cookbook (英文版) [Packt Publishing] Entity Framework 4.1 专家级开发 经典实例 (E-Book) ☆ 出版信息:☆ [作者信息] Devlin Liles, Tim Rayburn [出版...
请查看http://www.cnblogs.com/SINXUESONG/archive/2012/03/04/2379308.html
深入解读 Entity Framework 4.0和4.1