说好为大家带来一系列的文章,现在就写第二篇。开始之前,再啰嗦两句,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/02/01/using-dbcontext-in-ef-feature-ctp5-part-7-local-data.aspx

http://blogs.msdn.com/b/adonet/archive/2011/03/08/ef-feature-ctp5-code-first-model-with-master-detail-wpf-application.aspx

http://blogs.msdn.com/b/adonet/archive/2011/02/16/ef-feature-ctp5-code-first-and-winforms-databinding.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));

}

这里两个比较关键的函数是GetLocalEntitiesRegisterObjectStateManagerChangedEvent。前者是调用了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有所帮助吧!

系列博文之一: Entity Framework 4.1 DbContext使用记之一——如何查找实体? DbSet.Find函数的使用与实现。

系列博文之三: Entity Framework 4.1 DbContext使用记之三——如何玩转实体的属性值?

PS:同事开发了一个很cool的MSDN论坛桌面小工具,绝对给力!欢迎使用!(我也出了不少力啊

也欢迎到MSDN中文论坛ADO.NET与LINQ论坛来提问EF的问题啊,可以试试直接报我的名字Michael Sun,哈哈!

如需转发请注明原文出处,谢谢: http://www.cnblogs.com/LingzhiSun/archive/2011/03/25/EF41_Local.html

转载于:https://www.cnblogs.com/LingzhiSun/archive/2011/03/25/EF41_Local.html

Entity Framework 4.1 DbContext使用记之二——如何玩转本地实体? DbSet.Local属性的使用与实现...相关推荐

  1. Entity Framework 4.1 DbContext使用记之三——如何玩转实体的属性值?

    之前的两篇有关EF4.1的文章反响不错,感谢大家的支持!想体验EF4.1的新功能?RTW版本已经发布啦,http://www.microsoft.com/downloads/en/details.as ...

  2. ABP官方文档翻译 9.2 Entity Framework Core

    Entity Framework Core 介绍 DbContext 配置 在Startup类中 在模块PreInitialize方法中 仓储 默认仓储 自定义仓储 应用程序特定基础仓储类 自定义仓储 ...

  3. Entity Framework Core 软删除与查询过滤器

    注意:我使用的是 Entity Framework Core 2.0 (2.0.0-preview2-final).正式版发布后,功能可能存在变动. 继续探索Entity Framework Core ...

  4. Entity Framework 简介

    转贴:链接https://www.cnblogs.com/davidzhou/p/5348637.html 侵删,谢谢 第一篇:Entity Framework 简介 先从ORM说起吧,很多年前,由于 ...

  5. 使用Entity Framework Core,Swagger和Postman创建ASP.NET Core Web API的分步指南

    目录 介绍 背景 第1步:创建一个新项目 第2步:添加模型类 第3步:使用Entity Framework Core 第4步:添加数据库上下文和控制器 步骤5:在Package Manager控制台中 ...

  6. ADO.NET Entity Framework Beta2(五)/快速入门(实体框架)

    This quickstart illustrates a series of tasks that support the topics in Getting Started with the En ...

  7. mysql ado.net 实体数据模型_Visual Studio2017中如何让Entity Framework工具【ADO.NET实体数据模型】支持MYSQL数据源...

    熟悉Entity Framework应该对以下图片不陌生,他就是ADO.NET实体数据模型向导:可以将数据库的表自动生成模型类,或者创建Code First的模型文件. 但是这个模型向导默认只显示微软 ...

  8. 看我72变:解决Entity Framework中枚举类型与tinyint的映射问题

    <看我72变>是蔡依林的一首歌,"我要洗心革面,人定可以胜天,梦想近在眼前..." 在代码世界中,有一种常见的"变" -- 类型转变.这篇文章分享的 ...

  9. Entity Framework 学习

    Entity Framework 学习初级篇1--EF基本概况... 2 Entity Framework 学习初级篇2--ObjectContext.ObjectQuery.ObjectStateE ...

最新文章

  1. [雪峰磁针石博客]2018最佳12个开源或免费web服务器和客户端性能测试工具
  2. 29 _react-router说明
  3. javascript学习系列(22):数组中的reduceRight法
  4. Struts tiles入门(最最简单的例子)
  5. linux创建django项目,Ubuntu 16.04下配置Django项目
  6. jvm maxgcpausemillis 默认值_Tomcat和JVM的性能调优总结
  7. [Leetcode] spiral matrix ii 螺旋矩阵
  8. ECMAScript版本号总结
  9. 粗糙集理论(Rough Set Theory)
  10. 《软件工程》实训报告
  11. 16岁天才开发的Summly获李嘉诚种子投资
  12. MAC m1 node vue ui 编译项目时报错:node_modules/.bin/vue-cli-service: Permission denied 解决
  13. matlab模拟投硬币实验,利用几何画板模拟抛硬币实验
  14. MapReduce剥洋葱
  15. 正则表达式里“-“中划线的使用注意
  16. CISP——密码学基本概念(术语)
  17. 连英文都不懂怎么学python_不懂英文能学Python吗?
  18. 【雷达仿真 | FMCW TDMA-MIMO毫米波雷达信号处理仿真(可修改为DDMA-MIMO)】
  19. 记录一下近期工作-Qt实现tcp协议接收数据
  20. 计算机名改了怎么恢复,手把手练习win10系统改计算机名和工作组的恢复技巧

热门文章

  1. 史上超级详细:HashMap源码分析,你了解到源码的魅力了嘛
  2. 【PAT (Advanced Level) Practice】1120 Friend Numbers (20 分)
  3. 我就想要个两年1024徽章~!
  4. 【深度学习入门到精通系列】目标检测评估之P-R曲线深入理解
  5. host文件修改后无法保存的问题
  6. java方法6_6.1 JAVA方法入门
  7. 导出对象_从代数几何到导出代数几何:形变与逼近
  8. 网络推广——网络推广专员如何提升企业网站转化率?
  9. 思科ucs-b系列服务器,思科统一计算系统UCS B系列刀片推荐
  10. Java函数式折叠,循环,记忆化效率初识