实体框架中的POCO支持 - 第一部分 - 体验

  【译者按】 Entity Framework 1.0 发布也有一段时间了,但感觉用的人很少。其中一个很大的原因,也许就是不支持POCO。要知道,Entity Framework 1.0的做法是让你的实体从EF的基类继承而来,这对很多人,特别是崇尚DDD的人来说,那是一副难以下咽的药啊。曾有微软开发人员提供了一个 POCO Adapter,但那究竟不是正规的做法。Visual Studio 2010 和 .NET 4.0 提供了许许多多的新特性,真是让人激动,向往,大有一种回到.NET 1.0 刚出来时的感觉。春天啊(应该是夏天啊),你终于回来了(虽然早晨/晚上还是unseasonably冷)。其中的Entity Framework 4.0版本将提供POCO支持,对很多人来说,这是开始使用Entity Framework的时候了。ADO.NET 团队博客上贴出了一些关于EF和POCO的贴子,非常值得一读。

  【原文地址】POCO in the Entity Framework: Part 1 - The Experience

  【原文发表日期】 21 May 09 05:46 PM

  上个星期,我在《POCO初览》中提到了POCO实体支持是我们加到Entity Framework 4.0中的新功能之一。这个星期,我要对Entity Framework 4.0中POCO支持的细节进行深入讨论。

  要讨论的东西很多,包括

  • Entity Framework 4.0中总的POCO体验
  • POCO的变化跟踪
  • 关系修整
  • 复杂类型
  • 延迟(懒式)装载和显式装载
  • 最佳实践

  在这个贴子中,我将主要着重于总的体验,这样,你可以马上启用Entity Framework 4.0中的POCO支持。我将使用一个简单的例子做示范,这样,你可以看到在Entity Framework 4.0中使用POCO的感觉。我将使用Northwind数据库,在随后的贴子中,将继续建立在这个例子的基础之上。

第一步: 创建模型,关闭默认的代码生成

  虽然POCO允许你以透明持久化的方式编写自己的实体类,但还是有必要“接入”持久性和EF元数据,这样你的POCO实体可以从数据库中复原,以及持久化到数据库中。为实现这个,你还是需要使用实体框架设计器创建一个实体数据模型(Entity Data Model),或者提供跟你在Entity Framework 3.5中生成的完全一样的CSDL, SSDL 和 MSL 元数据文件。所以,首先,我将使用ADO.NET实体数据模型向导(Entity Data Model Wizard)来生成一个EDMX。

  

  1. 创建一个类库项目来定义你的POCO类型,我将其命名为NorthwindModel。这个项目与持久性毫不相关,对实体框架没有依赖性。
  2. 创建一个类库项目,它将包含与持久性相关的代码,我将其命名为NorthwindData。这个项目除了对NorthwindModel项目有依赖外,还对实体框架(System.Data.Entity)有依赖。
  3. NorthwindData 项目中添加新项,加一个名为“Northwind.edmx ”的ADO.NET实体数据模型(这么做将自动在项目中添加对实体框架的依赖)。
  4. 选择“从数据库生成”,给Northwind数据库建造模型
  5. 暂时只选CategoriesProducts这两个你感兴趣的表到你的实体数据模型中。

  至此,生成了可以为我所用的实体数据模型,但在开始编写代码前,还有最后一步:关闭代码生成。毕竟你感兴趣的是POCO啊,请去除负责从Northwind.edmx生成基于EntityObject代码的Custom Tool(自定义工具)属性,这将关闭你的模型的相应代码生成。

  

  现在,我们可以编写POCO实体了。

第二步: 编写你的POCO实体

  我将为Category和Product编写简单的POCO实体,这些类将加到NorthwindModel项目中去。注意,我在这里展示的,不应该看成是最佳实践,这里的意图只是示范可以工作的最简单的例子。在以后我们将根据需要将对这些例子进行扩展和定制,之后建立在其基础之上,使用RepositoryUnit of Work模式做进一步的扩展。

  这里是Category实体的样例代码:

1 public class Category
2     {
3         public int CategoryID { get; set; }
4         public string CategoryName { get; set; }
5         public string Description { get; set; }
6         public byte[] Picture { get; set; }
7         public List<Product> Products { get; set; }
8     }

  注意,在模型中我既为标量字段定义了属性,也定义了导航属性。模型中的导航属性(Navigation Property)转换成了List<Product>。

  类似地,Product实体可以这样编写:

 1 public class Product
 2     {
 3         public int ProductID { get; set; }
 4         public string ProductName { get; set; }
 5         public int SupplierID { get; set; }
 6         public string QuantityPerUnit { get; set; }
 7         public decimal UnitPrice { get; set; }
 8         public Int16 UnitsInStock { get; set; }
 9         public Int16 UnitsOnOrder { get; set; }
10         public Int16 ReorderLevel { get; set; }
11         public bool Discontinued { get; set; }
12         public Category Category { get; set; }
13     }

  在这个例子中,因为其间的关系,一个Product只允许属于一个Category,因此我们有一个对Category的引用(而不象Category中的导航属性,是一个List<T>集合)。

第三步: 编写你的实体框架上下文

  为把所有这些东西结合在一起,我所要做的最后一件事情是,提供一个上下文实现(就象使用默认的代码生成时你得到的ObjectContext实现一样)。上下文(context)是把持久化意识带进你的应用的胶水(glue),它允许你编写查询,将实体复原,以及将变化存回到数据库中去。该上下文将是NorthwindData项目的一部分。

  为简单起见,我将我们的上下文类包括在了包含实体类型的同个类库项目中了,但在我们讨论诸如Repository Unit of Work等模式时,我们将做这样的设置,即,你将拥有一个纯粹的POCO类库,不带任何一丝与持久性相关的东西。

  这里是针对我们场景的简单的上下文实现:

 1 public class NorthwindContext : ObjectContext
 2     {
 3         public NorthwindContext() : base("name=NorthwindEntities",
 4 "NorthwindEntities")
 5         {
 6             _categories = CreateObjectSet<Category>();
 7             _products = CreateObjectSet<Product>();
 8         }
 9
10         public ObjectSet<Category> Categories
11         {
12             get
13             {
14                 return _categories;
15             }
16         }
17         private ObjectSet<Category> _categories;
18
19         public ObjectSet<Product> Products
20         {
21             get
22             {
23                 return _products;
24             }
25         }
26         private ObjectSet<Product> _products;
27     }

  注意,ObjectSet<T> 是Entity Framework 4.0中引进的一个特殊的ObjectQuery<T>。

  就这么简单!现在你有了纯粹的POCO实体,一个简单的上下文,允许你编写象这样的查询:

1 NorthwindContext db = new NorthwindContext();
2 var beverages = from p in db.Products
3 where p.Category.CategoryName == "Beverages"
4 select p;

  从数据库中复原的实体是纯粹的POCO实体,你可以对这些实体做变动,将变动保存到数据库中,跟平常的EntityObjectIPOCO实体非常类似。你将得到实体框架提供的所有服务,唯一的区别是,你现在使用的是纯粹的POCO实体。

就我们的简化了的例子而言,尚有无数改进的可能性。但在那之前,我想先把一些基本的问题解决掉。

在使用POCO之前我需要一个实体数据模型么?

  是的,Entity Framework 4.0中的POCO支持只是去除了在你的实体类中带特定于持久性的关注的需求而已。但还是需要你提供CSDL/SSDL/MSL (总称EDMX)元数据,这样实体框架才能够将你的实体和元数据结合起来,以允许你访问数据。我们还在另外开发一个东西,它允许你做真正的“代码优先(code-first)”的开发,而不需要预先定义好的EDMX模型。这个功能的社区预览版将在几个月内在网上发布,一有机会我们就会将其加入实体框架。一如既往,你的反馈对我们极其有用。

我始终都只能手写这些实体和上下文么?

  不, Entity Framework 4.0中有一个非常强大和灵活的代码生成机制,该机制是基于T4之上的(Alex曾在这里的博客上讨论过)。你可以提供你自己的模板,允许你按照你自己选择的方式建造实体。我们还在努力,以提供一些标准的模板,可为你生成POCO实体。

使用POCO实体时,元数据是怎么映射的?

  在Entity Framework 3.5中,基于EntityObjectIPOCO的实体都是依赖着使用映射特性(attributes),对实体类型和属性进行修饰和映射到概念性模型中对应的元素的。Entity Framework 4.0 引入了基于约定(convention)的映射,以允许不用显式的修饰,就可将实体类型,属性,复杂类型和关系映射到概念性模型。一个简单的规则是,在你的POCO类中使用的实体类型名称,属性名称,和复杂类型名称必须匹配那些在概念性模型中定义了的相应名称。命名空间的名称不在考虑之中,类中的命名空间定义和概念性模型中的命名空间定义不必相符。

我的实体类中的所有属性都需要有公开的getters和setters么?

  你可以在你的POCO类型的属性上使用任何访问控制修饰符(access modifier),只要被映射的任何属性都不是虚拟的,以及你不需要局部信任(partial trust)支持。在局部信任下运行时,对你的实体类的访问控制修饰符的可见性有一些特定的要求。我们将对在涉及局部信任时,所支持的完整的访问控制修饰符集提供详细的文档。

对基于集合的导航属性都支持哪些集合类型?

  任何属于ICollection<T>的类型都是支持的。如果你对ICollection<T>类型的字段不以具体的类型初始化的话,那么从数据库中复原实体集合时, 将提供List<T>

我可以有单向的关系么?例如,我想在我的Product类中有一个 Category 属性,但在Category类中我不想要一个Products集合。

  是的,这是支持的。唯一的限制是,你的实体类型必须反映模型中所定义的东西。如果你不想拥有对应于关系的某一边的导航属性的话,那么你需要从模型中将其完全剔除。

POCO支持延迟(懒式)装载么?

  是的,POCO是通过使用代理类型来支持延迟(懒式)装载的,这些代理类型是在你的POCO类之上提供自动的懒式装载行为的。在讨论到延迟装载时,我们会对此做详述,在那之前,知道一下我们也支持通过使用“Include”来实现的早期装载(eager loading),象这样:

1 var beverageCategory = (from c in context.Categories.Include("Products")
2 where c.CategoryName == "Beverages"
3 select c).Single();

  如果我要使用延迟(懒式)装载的话,我不用这么做, 在讨论代理时我们会对此进行讨论。

修整(fix-up)关系

  要了解有2种类型的修整:1)查询时的修整, 2) 对你的实体/关系进行改动时的修整。

查询时的修整

  查询时的修整是在同一个ObjectContext上使用不同的查询来装载相关的实体时发生的。例如,如果我查询了一个分类实例“Beverages(饮料)”,之后又查询一个产品实例“Chai”(是在Beverages分类中的),我想要chai.Category 指向Beverages分类实例,不用我做额外的工作。

  这在今天是自动的,而且已经工作。

对你的实体/关系进行改动时的修整

  这是在添加/去除与另一个实体相关的实体或者改变关系时两个实体间的关系修整。设想一下这样的例子:在我创建一个名叫“Diet Chai”的新产品时,我想要将其与Beverages 分类相关联。

  在Entity Framework 4.0 Beta1 中,在这种情形下,POCO实体得不到自动的关系修整。在处理实体间的关系变动时,你需要确认你的POCO类型包含了在关系两头正确处理关系修整的逻辑。

  例如,在我的Northwind例子中,我在Category上定义了如下的方法,以支持添加/去除订单。

 1 public void AddProduct(Product p)
 2         {
 3             if (Products == null)
 4             {
 5                 Products = new List<Product>();
 6             }
 7
 8             if (!Products.Contains(p))
 9             {
10                 Products.Add(p);
11             }
12
13             p.Category = this;
14         }

  总的来说,使用象这样的模式来支持添加/去除相关项,要比使用关系集合来添加/去除相关实体为好。你还可以选择将实际由EF支持的集合的getter/setter变成私有或内部访问控制,来支持更为细颗粒的访问,但就象前面提到的那样,其中一些东西取决于你是否需要局部信任支持这样的需求。

  我们在这个“简短的综述”中对总的POCO体验做了一番讨论。要讨论的东西还有很多很多,下个星期我将继续这个讨论。与此同时,请看一下附件中的完整解决方案,如果你对我们在这里讨论的所有概念的相应例程代码感兴趣的话。请记住,你必须在运行这个例程的机器上安装一个本地Northwind数据库。

  在下一个贴子中,我们将看一下复杂类型,变化跟踪,代理,懒式装载和早期装载。在那之前,请阅读一下MSDN这里的关于POCO的文档,以了解Entity Framework 4.0中的POCO支持的细节。

  请告知我们你们的想法!

  Faisal Mohamood  Entity Framework的Program Manager

  附件: NorthwindPocoSamplePart1.zip

时间: 2024-11-09 06:12:50

实体框架中的POCO支持 - 第一部分 - 体验的相关文章

实体框架中的POCO支持 - 第三部分 - POCO的变动跟踪

在上一个POCO贴子里,我提到了跟踪POCO变动的两种可行性:基于快照的变动跟踪(Snapshot based Change Tracking) 和 使用代理的基于通知的变动跟踪(Notification based Change Tracking with Proxies). 在这个贴子里,我将对这两个选项做进一步的讨论,讨论它们的优缺点,以及使用它们的含意(implications).我们还将在<实体框架设计博客>上贴出针对至今为止受到的关于Entity Framework 4.0中POC

Entity Framework学习-实体框架中的code-first迁移

.net开发在涉及到操作数据库时,特别是访问SQL SERVER数据库时,经常需要使用一些ORM框架,最常用,且功能很强大的要数EF了.在使用EF进行涉及数据库的开发时,一般会涉及两种模式:1,DB first;2,Code first.相比前者,Code first比较灵活,适合敏捷开发,特别是数据库表结构经常变动的情况.在使用Code first时,经常会碰到对实体类的改动与数据库同步的问题,这时候我们就需要使用code first中的迁移功能,具体可以参考该文:https://msdn.m

关于EF实体框架中的 dbContext

EF4.1包括Code First和DbContext API.DbContext API为EF提供更多的工作方式:Code First,Database First和Model First. 使用DbContext构造函数 1. Code First约定连接 namespace Magic.Unicorn{    public class UnicornsContext : DbContext    {        public UnicornsContext()        // C#

实体框架6.0(Recipes)翻译系列 1 -----第一章 开始使用实体框架1

微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF版本更新太快,没人愿意去花时间翻译国外关于EF的书籍.使用Entity Framework开发已经有3年多了,但用得很肤浅,最近想深入学习,只好找来英文书<Entity Framework 6 Recipes>慢慢啃.首先需要说明的是,我英文不好,只是为了学习EF.把学习的过程写成博客,一是督促自

《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述 (转)

微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF版本更新太快,没人愿意去花时间翻译国外关于EF的书籍.使用Entity Framework开发已经有3年多了,但用得很肤浅,最近想深入学习,只好找来英文书<Entity Framework 6 Recipes>第二版,慢慢啃.首先需要说明的是,我英文不好,只是为了学习EF.把学习的过程写成博客,一

《Entity Framework 6 Recipes》翻译系列(2) -----第一章 开始使用实体框架之使用介绍 (转)

Visual Studio 我们在Windows平台上开发应用程序使用的工具主要是Visual Studio.这个集成开发环境已经演化了很多年,从一个简单的C++编辑器和编译器到一个高度集成.支持软件开发整个生命周期的多语言环境. Visual Studio以及它发布的工具和服务提供了:设计.开发.单元测试.调试.软件配置和管理.构建管理和持续集成等等.很少有开发人员因为还没有使用它而担心(注:作者应该是表达不用担心VS的能力),Visual Studio是一个完整的工具集.Visual Stu

《Entity Framework 6 Recipes》翻译系列 2 -----第一章 开始使用实体框架2

Visual Studio 我们在Windows平台上开发应用程序使用的工具主要是Visual Studio.这个集成开发环境已经演化了很多年,从一个简单的C++编辑器和编译器到一个高度集成.支持软件开发整个生命周期的多语言环境. Visual Studio以及它发布的工具和服务提供了:设计.开发.单元测试.调试.软件配置和管理.构建管理和持续集成等等.很少有开发人员因为还没有使用它而担心(注:作者应该是表达不用担心VS的能力),Visual Studio是一个完整的工具集.Visual Stu

Entity Framework 学习总结之一:ADO.NET 实体框架概述

http://www.cnblogs.com/xlovey/archive/2011/01/03/1924800.html ADO.NET 实体框架概述 新版本中的 ADO.NET 以新实体框架为特色.它使开发人员可以通过对象模型(而不是逻辑/关系数据模型)专注于数据.实体框架有助于将逻辑数据架构抽象为概念模型,并且允许以多种方式通过对象服务和名为“EntityClient”的新数据提供程序与概念模型交互. 实体框架使用概念层(ConceptualModels).映射层(Mappings)和逻辑

实体框架 5 性能注意事项

1.简介 对象关系映射框架是一种在面向对象的应用程序中提供数据访问抽象的便捷方式.对于 .NET 应用程序,Microsoft 推荐的 O/RM 是实体框架.但任何抽象都要考虑性能. 本白皮书旨在介绍在使用实体框架开发应用程序时的性能注意事项,使开发人员了解能够影响性能的实体框架内部算法,以及提供有关进行调查及在使用实体框架的应用程序中提高性能的提示.网络上有大量很好的有关性能的主题,我们还尽可能地指出这些资源的链接. 性能是一个很微妙的主题.对于使用实体框架的应用程序,可将本白皮书作为资源来帮