翻译的初衷以及为什么选择《Entity Framework 6 Recipes》来学习,请看本系列开篇

第八章 POCO

  对象不应该知道如何保存它们,加载它们或者过滤它们。这是软件开发中熟悉的口头禅,特别是在领域驱动设计中。这是一个聪明的做法,如果对象和持久化绑得太紧,以至于不能对领域对象进行单元测试、重构和复用。在ObjectContext上下对象中,实体框架为模型实体生成的类,高度依赖实体框架管道(Plumbing)。对于一此开发人员来说,这些类对持久化机制知道得太多了。而且,它们与特定的模型和映射关联太密切。幸好,我们还有另一个选项。

  实体框架还支持使用你自己创建的类来作为模型中的实体。术语叫做“普通公共运行时对象”(Plain Old CLR Object),通常被简单地叫做POCO,这并不意味着你的类普通而老掉牙。它仅仅是说,它不包含特定框架的引用,不需要来至第三方的代码,不实现任何第三方的专用接口,并且,它不需要别的任何程序集或者命名空间。你可以实现自己的领域对象,你会看到通过自定义的ObjectContext上下对象使它们适合模型。也就是说,凭借实体框架强大的能力,你可以选择任何架构模式。你同样也能使用DbContext为你产生POCO类。

  本章涵盖了多个关于POCO的小节。第一节展示POCO最基本的用法,剩下的小节集中在,实体的加载和实体框架使用对象状态保持同步。

  本章故意手工编写了大量的POCO类,是为了演示如何运用POCO。如果使用来至微软ADO.NET开发团队的T4模板,这些工作都将不复存在。

8-1  使用POCO

问题

  你想在你的项目中使用POCO。

解决方案

  假设你有如图8-1所示的数据模型。

图8-1. 一个关于客户和它的订单的数据库模型

  

  为了使用POCO类创建基于图8-1所示的数据库模型的实体框架模型,请按下面的步骤进行操作:

    1、右键你的项目,选择Add(增加) ➤New Item(新建项);

    2、选择Visual C#条目下的Data(数据)模板下的ADO.NET Entity Data Model(ADO.NET实体数据模型);

    3、选择Generate from database 从一个已存在的数据库创建模型;

    4、选择表order,OrderDetail,Customer和Product,单击下一步。在生成的模型中,实体Product有一个导航属性OrderDetails,它是关联产品的订单明细。在这里它不是必要的,因此将其删除(译注:实际上,没有删除)。完成后的模型如图8-2所示。

图8-2. 客户订单的模型

    

    5、我们使用生成的类作为的我们实体,默认情况下,实体框架6生成POCO实体类。 因此,所有的数据库访问代码都在一个单独的类中,实体被生成为普通的类。还可以在实体框架生成实体类之前关闭模型的代码生成功能,然后手工创建相同的实体类。 在这个版本中,代码生成策略已经被设置成None.代码清单8-1展示了我们模型中的类。

代码清单8-1. 我们模型的POCO类

  1. public partial class Customer
  2. {
  3. public Customer()
  4. {
  5. this.Orders = new HashSet<Order>();
  6. }
  7.  
  8. public int CustomerId { get; set; }
  9. public string ContactName { get; set; }
  10.  
  11. public virtual ICollection<Order> Orders { get; set; }
  12. }
  13.  
  14. public partial class Order
  15. {
  16. public Order()
  17. {
  18. this.OrderDetails = new HashSet<OrderDetail>();
  19. }
  20.  
  21. public int OrderId { get; set; }
  22. public int CustomerId { get; set; }
  23. public System.DateTime OrderDate { get; set; }
  24.  
  25. public virtual Customer Customer { get; set; }
  26. public virtual ICollection<OrderDetail> OrderDetails { get; set; }
  27. }
  28.  
  29. public partial class OrderDetail
  30. {
  31. public int OrderId { get; set; }
  32. public int ProductId { get; set; }
  33. public decimal UnitPrice { get; set; }
  34. public int Quantity { get; set; }
  35.  
  36. public virtual Order Order { get; set; }
  37. public virtual Product Product { get; set; }
  38. }
  39. public partial class Product
  40. {
  41. public Product()
  42. {
  43. this.OrderDetails = new HashSet<OrderDetail>();
  44. }
  45.  
  46. public int ProductId { get; set; }
  47. public string ProductName { get; set; }
  48. public decimal UnitPrice { get; set; }
  49.  
  50. public virtual ICollection<OrderDetail> OrderDetails { get; set; }
  51. }

注意,没有Product到OrdeDetail的关联,因为我们在设计器中移除了导航属性(译注:实际上,没有移除)

    6、为了使用POCO类,实体框架生成了DbContext的派生类。这个类将我们模型中的每个实体公布成ObjectSet<T>类型。 代码清章8-2演示了,这个类的定义。

代码清单8-2. 生成模型时创建的DbContext派生类

  1. public partial class EFRecipesEntities : DbContext
  2. {
  3. public EFRecipesEntities()
  4. : base("name=EFRecipesEntities")
  5. {
  6. }
  7.  
  8. protected override void OnModelCreating(DbModelBuilder modelBuilder)
  9. {
  10. throw new UnintentionalCodeFirstException();
  11. }
  12.  
  13. public DbSet<Customer> Customers { get; set; }
  14. public DbSet<Order> Orders { get; set; }
  15. public DbSet<OrderDetail> OrderDetails { get; set; }
  16. public DbSet<Product> Products { get; set; }
  17. }

  这样就完成了使用生成POCO类的模型,代码清单8-3演示了从模型中插入和获取数据

代码清单8-3. 使用POCO类

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. RunExample();
  6. }
  7.  
  8. static void RunExample()
  9. {
  10. using (var context = new EFRecipesEntities())
  11. {
  12. var tea = new Product { ProductName = "Green Tea", UnitPrice = 1.09M };
  13. var coffee = new Product
  14. {
  15. ProductName = "Colombian Coffee",
  16. UnitPrice = 2.15M
  17. };
  18. var customer = new Customer { ContactName = "Karen Marlowe" };
  19. var order1 = new Order { OrderDate = DateTime.Parse("10/06/13") };
  20. order1.OrderDetails.Add(new OrderDetail
  21. {
  22. Product = tea,
  23. Quantity = ,
  24. UnitPrice = 1.00M
  25. });
  26. order1.OrderDetails.Add(new OrderDetail
  27. {
  28. Product = coffee,
  29. Quantity = ,
  30. UnitPrice = 2.15M
  31. });
  32. customer.Orders.Add(order1);
  33. context.Customers.Add(customer);
  34. context.SaveChanges();
  35. }
  36.  
  37. using (var context = new EFRecipesEntities())
  38. {
  39. var query = context.Customers.Include("Orders.OrderDetails.Product");
  40. foreach (var customer in query)
  41. {
  42. Console.WriteLine("Orders for {0}", customer.ContactName);
  43. foreach (var order in customer.Orders)
  44. {
  45. Console.WriteLine("--Order Date: {0}--",
  46. order.OrderDate.ToShortDateString());
  47. foreach (var detail in order.OrderDetails)
  48. {
  49. Console.WriteLine(
  50. "\t{0}, {1} units at {2} each, unit discount: {3}",
  51. detail.Product.ProductName,
  52. detail.Quantity.ToString(),
  53. detail.UnitPrice.ToString("C"),
  54. (detail.Product.UnitPrice - detail.UnitPrice).ToString("C"));
  55. }
  56. }
  57. }
  58. }
  59. Console.WriteLine("Enter input to exit:");
  60. string line = Console.ReadLine();
  61. if (line == "exit")
  62. {
  63. return;
  64. };
  65. }
  66. }

代码清单8-3的输出如下:

  1. Orders for Karen Marlowe
  2. --Order Date: //--
  3. Green Tea, units at $1.00 each, unit discount: $0.09
  4. Colombian Coffee, units at $2.15 each, unit discount: $0.00

原理

  生成POCO类,是当前版本实体框架的默认特性。代码生成策略的属性值已经被设置为None。上下文对象也是被单独生成。所以POCO类中已经没有了数据访问代码。

  如果与模型中实体对应的所有类已经被创建,它们简单,洁净。这样的话就,没有代码生成,没有上下文被生成。为了实现适合我们模型和实体的上下文对象,派生至DbContext的一个新类在数据模型生成时就被创建了。这个类还提供了对应每个实体的,类型为DbSet<T>的属性。 默认情况下,我们的上下文对象EFRecipesEntities,已经包含了能连接数据库的构造函数代码。

实体框架交流QQ群:  458326058,欢迎有兴趣的朋友加入一起交流

谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/VolcanoCloud/

《Entity Framework 6 Recipes》中文翻译系列 (42) ------ 第八章 POCO之使用POCO的更多相关文章

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

    微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...

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

    Visual Studio 我们在Windows平台上开发应用程序使用的工具主要是Visual Studio.这个集成开发环境已经演化了很多年,从一个简单的C++编辑器和编译器到一个高度集成.支持软件 ...

  3. 《Entity Framework 6 Recipes》翻译系列 (4) -----第二章 实体数据建模基础之从已存在的数据库创建模型

    不知道对EF感兴趣的并不多,还是我翻译有问题(如果是,恳请你指正),通过前几篇的反馈,阅读这个系列的人不多.不要这事到最后成了吃不讨好的事就麻烦了,废话就到这里,直奔主题. 2-2 从已存在的数据库创 ...

  4. 《Entity Framework 6 Recipes》翻译系列 (3) -----第二章 实体数据建模基础之创建一个简单的模型

    第二章 实体数据建模基础 很有可能,你才开始探索实体框架,你可能会问“我们怎么开始?”,如果你真是这样的话,那么本章就是一个很好的开始.如果不是,你已经建模,并在实体分裂和继承方面感觉良好,那么你可以 ...

  5. 《Entity Framework 6 Recipes》翻译系列 (5) -----第二章 实体数据建模基础之有载荷和无载荷的多对多关系建模

    2-3 无载荷(with NO Payload)的多对多关系建模 问题 在数据库中,存在通过一张链接表来关联两张表的情况.链接表仅包含连接两张表形成多对多关系的外键,你需要把这两张多对多关系的表导入到 ...

  6. 《Entity Framework 6 Recipes》中文翻译系列 (43) ------ 第八章 POCO之使用POCO加载实体

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-2  使用POCO加载关联实体 问题 你想使用POCO预先加载关联实体. 解决方 ...

  7. 《Entity Framework 6 Recipes》中文翻译系列 (44) ------ 第八章 POCO之POCO中使用值对象和对象变更通知

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-4  POCO中使用值对象(Complex Type--也叫复合类型)属性 问题 ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 (45) ------ 第八章 POCO之获取原始对象与手工同步对象图和变化跟踪器

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-6  获取原始对象 问题 你正在使用POCO,想从数据库获取原始对象. 解决方案 ...

  9. 《Entity Framework 6 Recipes》中文翻译系列 (46) ------ 第八章 POCO之领域对象测试和仓储测试

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-8  测试领域对象 问题 你想为领域对象创建单元测试. 这主要用于,测试特定的数 ...

随机推荐

  1. Scrapy框架实现爬虫

    实战中的遇到的问题总结: 1.

  2. 使用Packet Sniffer抓包和分析(z-stack协议)

    以下内容仅是自己学习总结,可能会有错误,有发现问题的欢迎指正(图片可以自己放大,还是比较清晰的). 1.协调器上电,其他设备均不上电,抓包如下: 通过观察可以发现,协调器建立网络成功后,会以15秒为周 ...

  3. java 随机获取国内IP

    /* * 随机生成国内IP地址 */ public static String getRandomIp(){ //ip范围 int[][] range = {{607649792,608174079} ...

  4. Unity插件使用总结

    移动文件夹位置会引起错误的插件:EasySave2.MaterialUI.Gamestrap UI.Beautify

  5. SOAPUI使用教程-从现有的服务创建REST模拟服务

    从现有的服务创建REST模拟服务 在您的项目创建一个模拟服务从现有的服务是非常简单的. 右键单击 服务 . 选择 生成模拟服务 . 打开一个对话框窗口. 输入一个描述性的名称. 点击 好吧 . 创建模 ...

  6. Android 照相 滤镜

    android-image-filter 19种相片滤镜,使用也简单,all filters in file BitmapFilter.java : Bitmap newBitmap = Bitmap ...

  7. uva12063数位dp

    辣鸡军训毁我青春!!! 因为在军训,导致很长时间都只能看书yy题目,而不能溜到机房鏼题 于是在猫大的帮助下我发现这道习题是数位dp 然后想起之前讲dp的时候一直在补作业所以没怎么写,然后就试了试 果然 ...

  8. 【BZOJ3156】防御准备 斜率优化DP

    裸题,注意:基本的判断(求Min还是Max),因为是顺着做的,且最后一个a[i]一定要取到,所以是f[n]. DP:f[i]=min(f[j]+(i-j-1)*(i-j)/2+a[i]) 依旧设x&g ...

  9. iOS中 将 颜色转化成图片

    定义一个类方法: 声明: + (UIImage *)imageFromColor:(UIColor *)color; 实现: + (UIImage *)imageFromColor:(UIColor ...

  10. [ios] 定位报错Error Domain=kCLErrorDomain Code=0 "The operation couldn’t be completed. (kCLErrorDomain error 0.)"

    Error Domain=kCLErrorDomain Code=0 "The operation couldn’t be completed. (kCLErrorDomain error ...