zoukankan      html  css  js  c++  java
  • 《Entity Framework 6 Recipes》中文翻译系列 (42) ------ 第八章 POCO之使用POCO

    翻译的初衷以及为什么选择《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 = 4,
    24                     UnitPrice = 1.00M
    25                 });
    26                 order1.OrderDetails.Add(new OrderDetail
    27                 {
    28                     Product = coffee,
    29                     Quantity = 3,
    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                                 "	{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的输出如下:

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

    原理

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

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

     

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

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

  • 相关阅读:
    第一章:进销存系统基本功能
    SpringBoot 整合 Docker
    Java的脚本机制、编译器API
    Java 定时任务
    监听文件修改的四种方法
    SpringBoot Actuator — 埋点和监控
    Kafka消息队列
    OpenSSL配置HTTPS
    Java 国际化
    备忘录模式
  • 原文地址:https://www.cnblogs.com/VolcanoCloud/p/4545314.html
Copyright © 2011-2022 走看看