《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所示的数据库关系图的 ...
随机推荐
- Spring的JDBC模板
Spring对持久层技术支持 JDBC : org.springframework.jdbc.core.JdbcTemplate Hibernate3.0 : org.springframework. ...
- Codeforces 721E Road to Home
题意 输入第一行有4个数,分别为\(L,n,p,t\),分别表示总长度为\(L\)的路,中间有\(n\)个互不相交的区间,现在要用长度为\(p\)的小木棒从左往右铺路(木棒不能被折断,也不能有重叠,且 ...
- CODEVS1090 加分二叉树
codevs1090 加分二叉树 2003年NOIP全国联赛提高组 题目描述 Description 设一个n个节点的二叉树tree的中序遍历为(l,2,3,…,n),其中数字1,2,3,…,n为节点 ...
- javascript判断数据类型的各种方法
一.Object.prototype.toString方法(摘自http://javascript.ruanyifeng.com/stdlib/object.html#toc3) //不同数据类型的O ...
- java DOM4J 读取XML
最近学习Java,在处理XML文档的时候,查阅相关资料,发现了DOM4J这个jre库,相对C#的XML处理来说,功能还算是跟得上 下面展示一篇我自己写的一个XML读取测试 import java.ut ...
- Object-C 1.0 第三章:面向对象编程基础知识(OOP)
1. 间接(indirection) 1.1 变量和间接(使用变量来代替一些数字) 1.2 使用文件名的间接 const 表示一个变量不允许 ...
- linux下的tcp连接超时
最近需要写一个linux下的通信程序, 通信模块用的是Qt的QTcpSocket. 最后程序需要增加一个断网检测, 在windows下调试没问题, 拔网线, 断网口都能马上检测到, 但到了部署到lin ...
- 纯css来实现提示框
用js用多了,就疏忽了最基本的css了---用title属性来实现提示框.下面言归正传------如何用css实现提示框: 1.利用title属性来实现鼠标滑过某个元素时,实现提示整段内容的功能(利用 ...
- 安装WampServer时出现的问题(丢失VCRUNTIME140.dll或MSVCR110.dll)以及解决办法
今天,在安装WampServer时,刚开始提示了"丢失VCRUNTIME140.dll"的问题. 我就网上查了一下,结果大家说是没有安装VC++,然后我就按照网友们提供的网址去下载 ...
- flex的兼容
父容器的 display 属性: .box{ display: -webkit-box; /* 老版本语法: Safari, iOS, Android browser, older WebKit br ...