zoukankan      html  css  js  c++  java
  • 《Entity Framework 6 Recipes》中文翻译系列 (10) 第二章 实体数据建模基础之两实体间Isa和Hasa关系建模、嵌入值映射

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

    2-11 两实体间Is-a和Has-a关系建模

    问题

      你有两张有Is-a和Has-a关系的表,你想将他们建模成两实体间的Is-a和Has-a关系。

    解决方案

      假设你在数据库中,有两张描述风景名胜公园和公园地址的表,Loacation和Part。在应用中,park是location的简单(simply)类型(译注:从上下文看应该是指子类)。另外,一个park有一个拥有邮寄地址的管理办公室,这个地址同样也可以用表location来表示。那么,一个park实体既是Location的派生类,又有一个与管理办公室相对应的地址。办公室完全有可能不位于公园内,也许几个公园的管理办公室都在附近的同一个小镇上。图2-21显示表Park和Location的数据库关系图。

    图2-21 表Location和Park的Has-a和Is-a关系

      按下面的步骤,为这两个关系建模:

        1、右键你的项目,选择Add(增加) ➤New Item(新建项),然后选择Visual C#条目下的Data模板下的ADO.NET Entity Data Model(ADO.NET实体数据模型)。

        2、选择Generate from database 从一个已存在的数据库创建模型,点击Next(下一步)。

        3、可以选择一个已存在的数据库连接,也可以选择新建一个数据库连接。

        4、在选择数据库窗口,选择表Location和Park。后勾选上确定所生成对象名称的单复数形式、在模型中包含外键列复选框。点击Finish(完成)

        5、删除实体数据模型向导生成的关联1-to-0或者1;

        6、右键Location实体,选择 Add(增加) ➤Inheritance(继承)。选择实体Park作为派生类实体,Location作为基类实体;

        7、从Park实体类型删除属性ParkId;

        8、单击Part实体并查看映射详细信息窗口,如果映射详细信息窗口未显示。选择工具菜单View(视图) ➤Other Windows(其它窗口) ➤Entity Data Model Mapping Details(实体数据模型映射详细信息)。在映射详细信息窗口中将ParkId列映射到LocationId属性;

        9、修改Park实体类型的导航属性名为Office,它代表park的办公位置。

        完成后的模型如图2-22所示。

    图2-22 Park继承自Loacation,一个Park is-a location,一个Park has-a 它的办公location

    原理

      在这个示例中,实体间超过一个关联。我们使用TPT继承映射创建了一个Is-a关系,实体Loaction为基类,实体Park为派生类。我们同时使用一个1对多关联在Locaton和Park实体间创建一个Has-a关系。

      在代码清单2-26中,我们演示了创建一个Park实体实例,因为Is-a关系,等同我们也创建了一个Loacation实例。 我们把管理办公室地址附加给Park,这样会导致在Location表中插入第二行。

     代码清单2-26 创建和获取Park和Location实体

     1 using (var context = new EF6RecipesContext()) {
     2                 var park = new Park {
     3                     Name = "11th Street Park",
     4                     Address = "801 11th Street",
     5                     City = "Aledo",
     6                     State = "TX",
     7                     ZIPCode = "76106"
     8                 };
     9                 var loc = new Location {
    10                     Address = "501 Main",
    11                     City = "Weatherford",
    12                     State = "TX",
    13                     ZIPCode = "76201"
    14                 };
    15                 park.Office = loc;
    16                 context.Locations.Add(park);
    17                 park = new Park {
    18                     Name = "Overland Park",
    19                     Address = "101 High Drive",
    20                     City = "Springtown",
    21                     State = "TX",
    22                     ZIPCode = "76081"
    23                 };
    24                 loc = new Location {
    25                     Address = "8705 Range Lane",
    26                     City = "Springtown",
    27                     State = "TX",
    28                     ZIPCode = "76081"
    29                 };
    30                 park.Office = loc;
    31                 context.Locations.Add(park);
    32                 context.SaveChanges();
    33             }
    34 
    35 
    36             using (var context = new EF6RecipesContext()) {
    37                 context.ContextOptions.LazyLoadingEnabled = true;
    38                 Console.WriteLine("-- All Locations -- ");
    39                 foreach (var l in context.Locations) {
    40                     Console.WriteLine("{0}, {1}, {2} {3}", l.Address, l.City,
    41                     l.State, l.ZIPCode);
    42                 }
    43                 Console.WriteLine("--- Parks ---");
    44                 foreach (var p in context.Locations.OfType<Park>()) {
    45                     Console.WriteLine("{0} is at {1} in {2}", p.Name, p.Address, p.City);
    46                     Console.WriteLine("\tOffice: {0}, {1}, {2} {3}", p.Office.Address,
    47                     p.Office.City, p.Office.State, p.Office.ZIPCode);
    48                 }
    49             }

      代码清单2-26的输出为:

    -- All Locations --501 Main, Weatherford, TX 76201
    801 11th Street, Aledo, TX 76106
    8705 Range Lane, Springtown, TX 76081
    101 High Drive, Springtown, TX 76081
    --- Parks ---11th Street Park is at 801 11th Street in Aledo
    Office: 501 Main, Weatherford, TX 76201
    Overland Park is at 101 High Drive in Springtown
    Office: 8705 Range Lane, Springtown, TX 76081

      

    2-12 创建、修改和映射复合类型

    问题

      你想创建一个复合类型,将它设置实体的一个属性,然后映射该属性到数据库表中的多列。 (译注:这就是领域模型中的嵌入值映射,这对喜欢DDD的人来说,这小节和前面的TPT,TPH都应该掌握

    解决方案

      假设你在数据库中有图2-23所示的表,你想为FirtstName和LastName列创建一个复合类型的属性Name. 为AddressLine1、AddressLine2、City、State以及ZIPCode列创建一个复合类型属性Address。这些复合类型在模型中都是实体中的属性,如图2-24所示。

     

    图2-23 Agent实体和他的复合属性name和address

    图2-24 表Agent

       按下面的步骤,为Name和Address复合类型建模:

        1、右键你的项目,选择Add(增加) ➤New Item(新建项),然后选择Visual C#条目下的Data模板下的ADO.NET Entity Data Model(ADO.NET实体数据模型)。

        2、选择Generate from database 从一个已存在的数据库创建模型,点击Next(下一步)。

        3、可以选择一个已存在的数据库连接,也可以选择新建一个数据库连接。

        4、在选择数据库窗口,选择表Agent。后勾选上确定所生成对象名称的单复数形式、在模型中包含外键列复选框。点击Finish(完成);

        5、选择FirstName和LastName属性,右键,选择Refactor(重构)➤ Into Complex Type(移动到新的复合类型);

        6、在模型浏览器中,将这个新的复合类型ComplexType1重命名为Name,这将改变这个类型的名字。在实体Agent上,重命名属性ComplexTypePeroperty为Name,这将改变属性的名称。

        7、为了演示另一种方法,我们从头开始创建下一个复合类型,在设计窗口中右键,选择Add(增加)➤Complex Type(复合类型);

        8、在模型浏览器中,重命名这个新创建的复合类型ComplexType1的名称为Address;

        9、在实体Agent中选择属性AddressLine1、AddressLine2、City、State以及ZipCode,右键选择Cut(剪切),在模型浏览器中将这些属性粘贴到复合类型Address;

        10、右键实体Agent,选择Add(添加) ➤Complex Property(复合类型)。将其重命名为Address;

        11、右键新创建的Address属性,选择Properties(属性),改变其类型为Address。这将改变新创建的属性的类型为Address复合类型;

        12、在映射详细信息窗口,查看Agnet映射信息。将表Agent中的列映射到我们刚创建的两个复合类型上,如图2-25所示。

     

    图2-25 映射复合类型字段到Agent表

    原理

      复合类型允许你将一组属性包含到一个用于实体属性的单独类型,一个复合类型可以包含标量属性和其它的复合类型,但不能包含导航属性和实体集合。一个复合类型不能是一个实体键。复合类型不能在上下文对象中被跟踪。

      类型为复合类型的属性不能为null,当你使用包含复合类型属性的实体时,你必须记住这条准则。偶尔,当复合类型属性的值在特定的操作中不重要时,我可以为其创建一个虚值(dummy value),使它有一个不为null的值。

      当你修改了复合类型属性中的任一字段,这个属性将被实体框架标记为已改变(changed),一个将更新复合类型所有字段的更新语句会被生成。

      代码清单2-27 演示在模型中插入一些数据,然后再显示它们

    代码清单2-27.插入Agents,然后从模型中查询数据

     1  using (var context = new EF6RecipesContext()) {
     2                 var name1 = new Name { FirstName = "Robin", LastName = "Rosen" };
     3                 var name2 = new Name { FirstName = "Alex", LastName = "St. James" };
     4                 var address1 = new Address {
     5                     AddressLine1 = "510 N. Grant",
     6                     AddressLine2 = "Apt. 8",
     7                     City = "Raytown",
     8                     State = "MO",
     9                     ZIPCode = "64133"
    10                 };
    11                 var address2 = new Address {
    12                     AddressLine1 = "222 Baker St.",
    13                     AddressLine2 = "Apt.22B",
    14                     City = "Raytown",
    15                     State = "MO",
    16                     ZIPCode = "64133"
    17                 };
    18 
    19                 context.Agents.Add(new Agent { Name = name1, Address = address1 });
    20                 context.Agents.Add(new Agent { Name = name2, Address = address2 });
    21                 context.SaveChanges();
    22             }
    23             using (var context = new EF6RecipesContext()) {
    24                 Console.WriteLine("Agents");
    25                 foreach (var agent in context.Agents) {
    26                     Console.WriteLine("{0} {1}", agent.Name.FirstName, agent.Name.LastName);
    27                     Console.WriteLine("{0}", agent.Address.AddressLine1);
    28                     Console.WriteLine("{0}", agent.Address.AddressLine2);
    29                     Console.WriteLine("{0}, {1} {2}", agent.Address.City,
    30                     agent.Address.State, agent.Address.ZIPCode);
    31                     Console.WriteLine();
    32                 }
    33             }

    代码清单2-27的输入如下:

    Agents
    Robin Rosen
    510 N. Grant
    Apt. 8
    Raytown, MO 64133
    Alex St. James
    222 Baker St.
    Apt.22B
    Raytown, MO 64133


     

    本篇稍微有点长,感觉你的耐心阅读,转载请注明出处:http://www.cnblogs.com/VolcanoCloud/p/4492614.html                

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

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

           

    版权所有,转载请注明出处 付灿的技术博客
  • 相关阅读:
    4-9 内置函数和匿名函数的题
    4-09 试题
    4--2日 函数 装饰器 作业题
    if 语句
    4-4日 内置函数,匿名函数
    4-4日 列表推导式,生成器推导式
    4-3日 迭代器 生成器
    4-2日装饰器,带参数的装饰器
    python 函数名 、闭包 装饰器 day13
    [LeetCode]-DataBase-Department Top Three Salaries
  • 原文地址:https://www.cnblogs.com/VolcanoCloud/p/4492614.html
Copyright © 2011-2022 走看看