《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所示的数据库关系图的 ...
随机推荐
- ubuntu14 备份
备份命令 # tar cvpjf backup.tar.bz2 –exclude=/proc –exclude=/lost+found –exclude=/backup.tar.bz2 –exclud ...
- jshint 一些选项(转载)
内容来自: http://www.cnblogs.com/qianduanjingying/p/6185793.html 一些变量的作用: http://www.cnblogs.com/CloudMu ...
- 学习微信小程序之css7
盒模型 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...
- Spartan Exploit Kit分析
之前都是调试flash的漏洞,相关的样本接触较少,碰巧看到一篇不错的分析,尝试了一下,留个记录. 调试flasher样本一般建议使用调试版的flash player,在调试版本下可以输出swf文件运行 ...
- FZU 1914 单调队列
题目链接:http://acm.fzu.edu.cn/problem.php?pid=1914 题意: 给出一个数列,如果它的前i(1<=i<=n)项和都是正的,那么这个数列是正的,问这个 ...
- java spring 配置文件的读取
java读取本地配置文件主要分为两类,一类为class相关文件或子文件夹下,一类文件 为jar包外配置文件. class相关文件夹或子文件夹下读取配置文件可以使用Object.class.getRes ...
- Android四种点击事件和五中存储方式
Android点击事件的四种实现方式 1.内部类实现onClickListenter接口 bt_login.setOnClickListener(new MyListener()); class My ...
- java-并发-高级并发对象2
浏览以下内容前,请点击并阅读 声明 并发集合 java.util.concurrent包包含了许多对于java集合框架的补充,根据提供的接口可以将这些集合分为以下几类: BlockingQueue 定 ...
- [VijosP1656]萌萌赶考 题解
题目大意: 有一个地图,有障碍,不能重复经过一点(但起点可以),判断能否恰好在t时刻从起点到达终点. 思路: 一开始DFS一遍,30分,于是要有优化减枝.最重要的是从起点到终点的距离的奇偶性是与起点与 ...
- mac下配置xampp多端口
首先下载并安装完XAMPP软件. 第一步: 打开XAMPP安装目录,找到配置文件. 如:/Applications/XAMPP/etc/httpd.conf 打开后查找 Listen 80 会看到以下 ...