《Entity Framework 6 Recipes》中文翻译系列 (10) -----第二章 实体数据建模基础之两实体间Is-a和Has-a关系建模、嵌入值映射
翻译的初衷以及为什么选择《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实体
using (var context = new EF6RecipesContext()) {
var park = new Park {
Name = "11th Street Park",
Address = "801 11th Street",
City = "Aledo",
State = "TX",
ZIPCode = ""
};
var loc = new Location {
Address = "501 Main",
City = "Weatherford",
State = "TX",
ZIPCode = ""
};
park.Office = loc;
context.Locations.Add(park);
park = new Park {
Name = "Overland Park",
Address = "101 High Drive",
City = "Springtown",
State = "TX",
ZIPCode = ""
};
loc = new Location {
Address = "8705 Range Lane",
City = "Springtown",
State = "TX",
ZIPCode = ""
};
park.Office = loc;
context.Locations.Add(park);
context.SaveChanges();
} using (var context = new EF6RecipesContext()) {
context.ContextOptions.LazyLoadingEnabled = true;
Console.WriteLine("-- All Locations -- ");
foreach (var l in context.Locations) {
Console.WriteLine("{0}, {1}, {2} {3}", l.Address, l.City,
l.State, l.ZIPCode);
}
Console.WriteLine("--- Parks ---");
foreach (var p in context.Locations.OfType<Park>()) {
Console.WriteLine("{0} is at {1} in {2}", p.Name, p.Address, p.City);
Console.WriteLine("\tOffice: {0}, {1}, {2} {3}", p.Office.Address,
p.Office.City, p.Office.State, p.Office.ZIPCode);
}
}
代码清单2-26的输出为:
-- All Locations -- Main, Weatherford, TX
11th Street, Aledo, TX
Range Lane, Springtown, TX
High Drive, Springtown, TX
--- Parks ---11th Street Park is at 11th Street in Aledo
Office: Main, Weatherford, TX
Overland Park is at High Drive in Springtown
Office: Range Lane, Springtown, TX
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,然后从模型中查询数据
using (var context = new EF6RecipesContext()) {
var name1 = new Name { FirstName = "Robin", LastName = "Rosen" };
var name2 = new Name { FirstName = "Alex", LastName = "St. James" };
var address1 = new Address {
AddressLine1 = "510 N. Grant",
AddressLine2 = "Apt. 8",
City = "Raytown",
State = "MO",
ZIPCode = ""
};
var address2 = new Address {
AddressLine1 = "222 Baker St.",
AddressLine2 = "Apt.22B",
City = "Raytown",
State = "MO",
ZIPCode = ""
}; context.Agents.Add(new Agent { Name = name1, Address = address1 });
context.Agents.Add(new Agent { Name = name2, Address = address2 });
context.SaveChanges();
}
using (var context = new EF6RecipesContext()) {
Console.WriteLine("Agents");
foreach (var agent in context.Agents) {
Console.WriteLine("{0} {1}", agent.Name.FirstName, agent.Name.LastName);
Console.WriteLine("{0}", agent.Address.AddressLine1);
Console.WriteLine("{0}", agent.Address.AddressLine2);
Console.WriteLine("{0}, {1} {2}", agent.Address.City,
agent.Address.State, agent.Address.ZIPCode);
Console.WriteLine();
}
}
代码清单2-27的输入如下:
Agents
Robin Rosen
N. Grant
Apt.
Raytown, MO
Alex St. James
Baker St.
Apt.22B
Raytown, MO
本篇稍微有点长,感觉你的耐心阅读,转载请注明出处:http://www.cnblogs.com/VolcanoCloud/p/4492614.html
实体框架交流QQ群: 458326058,欢迎有兴趣的朋友加入一起交流
谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/VolcanoCloud/
《Entity Framework 6 Recipes》中文翻译系列 (10) -----第二章 实体数据建模基础之两实体间Is-a和Has-a关系建模、嵌入值映射的更多相关文章
- 《Entity Framework 6 Recipes》翻译系列 (3) -----第二章 实体数据建模基础之创建一个简单的模型
第二章 实体数据建模基础 很有可能,你才开始探索实体框架,你可能会问“我们怎么开始?”,如果你真是这样的话,那么本章就是一个很好的开始.如果不是,你已经建模,并在实体分裂和继承方面感觉良好,那么你可以 ...
- 《Entity Framework 6 Recipes》翻译系列 (4) -----第二章 实体数据建模基础之从已存在的数据库创建模型
不知道对EF感兴趣的并不多,还是我翻译有问题(如果是,恳请你指正),通过前几篇的反馈,阅读这个系列的人不多.不要这事到最后成了吃不讨好的事就麻烦了,废话就到这里,直奔主题. 2-2 从已存在的数据库创 ...
- 《Entity Framework 6 Recipes》翻译系列 (5) -----第二章 实体数据建模基础之有载荷和无载荷的多对多关系建模
2-3 无载荷(with NO Payload)的多对多关系建模 问题 在数据库中,存在通过一张链接表来关联两张表的情况.链接表仅包含连接两张表形成多对多关系的外键,你需要把这两张多对多关系的表导入到 ...
- 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述
微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...
- 《Entity Framework 6 Recipes》翻译系列(2) -----第一章 开始使用实体框架之使用介绍
Visual Studio 我们在Windows平台上开发应用程序使用的工具主要是Visual Studio.这个集成开发环境已经演化了很多年,从一个简单的C++编辑器和编译器到一个高度集成.支持软件 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (8) -----第二章 实体数据建模基础之继承关系映射TPT
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 2-8 Table per Type Inheritance 建模 问题 你有这样一 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (9) -----第二章 实体数据建模基础之继承关系映射TPH
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 2-10 Table per Hierarchy Inheritance 建模 问题 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (7) -----第二章 实体数据建模基础之拆分实体到多表以及拆分表到多实体
2-6 拆分实体到多表 问题 你有两张或是更多的表,他们共享一样的主键,你想将他们映射到一个单独的实体. 解决方案 让我们用图2-15所示的两张表来演示这种情况. 图 2-15,两张表,Prodeuc ...
- 《Entity Framework 6 Recipes》中文翻译系列 (6) -----第二章 实体数据建模基础之使用Code First建模自引用关系
2-5 使用Code First建模自引用关系 问题 你的数据库中一张自引用的表,你想使用Code First 将其建模成一个包含自关联的实体. 解决方案 我们假设你有如图2-14所示的数据库关系图的 ...
随机推荐
- mysql乐观锁总结和实践
乐观锁介绍: 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突 ...
- 搜索技巧<转>
平时工作,搜索引擎是少不了的,作为程序员,当然首推 Google.这里简单介绍下几个 Google 搜索的小技巧,方便别人也方便自己查阅. ps:以下所有操作,均可以在 「谷歌搜索首页 -> 设 ...
- install hdp 2.2 on ubuntu 14.04
http://www.swiss-scalability.com/2014/12/install-hdp-22-on-ubuntu-1404-trusty.html 在新加节点上运行 sed -e & ...
- bzoj3123: [Sdoi2013]森林
题面传送门 复出的第一道题.. md就遇到坑了.. 简单来说就是可持久化线段树+启发式合并啊.. 感觉启发式合并好神奇好想学 每一次建边就暴力合并,每一个节点维护从根到它的权值线段树 按照题面的话最省 ...
- 如何在Web引用中使用项目自定义的类
这个是老架构了,不推荐现在这么用,维护一个老项目记录一下. 项目中WebService和客户端是在一个解决方案下,实体类是一个公用的Project,如果使用Web引用自动生成的类会缺少一些实体类定义的 ...
- 二分图&网络流&最小割等问题的总结
二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 技巧: 1.拆点为边,即一个点有限制,可将其转化为边 BZOJ1066, ...
- appium过程中的问题
1.在eclipse中点击Genymotion Virtual Device Manager ,选择虚拟设备,点击start后,无反应. 解决方法:Help/Install New Softwa ...
- C,C++
C与C++的Struct有何区别,Java有Struct吗,C++里Struct与Class区别: C++虚析构函数作用: static静态变量初始化: 深复制与浅复制区别: const * int ...
- 基于node.js的压缩合并安装
1.构建工具(grunt,gulp) 下载地址:http://gruntjs.cn/http://gruntjs.com/ (1)安装nodejs(http://www.nodejs.org/) 验证 ...
- 关于iOS后台问题( 一 )(ios后台刷新,后台定位,后台下载,真后台)
关于iOS的后台,以下引用一些文段进行一下脑补,请同学们大致看一下,有个基础,原文出处 -------------------------------------------------------- ...