《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

时间:2021-12-09 04:24:53

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

6-13  在基类中应用条件

问题

  你想从一个已存在的模型中的实体派生一个新的实体,允许基类被实例化。

解决方案

  假设你有如图6-20所示的模型。

《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

图6-20 包含Invoice实体的模型

  这个模型只包含一个单独的实体Invoice(发货单)。我们想从Invoice派生一个新的实体,它表示删除掉的发货单。这将允许我们以更清晰的业务逻辑来分别对有效的发货单和已删除掉的发货进行不同的操作。按下面的步骤,添加这个派生类型:

    1、在Mapping Details window(映射详细信息窗口)查看实体Invoice的信息,在IsDeleted列上添加一个条件,When IsDeleted =0(当IsDeleted列值为0),如图6-21所示。

《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

图6-21 当IsDeleted列为0时映射Invoice实体

    2、现在IsDeleted列被用作条件,我们需要将其从实体的标量属性中移除。在实体Invoice的属性IsDeleted上右键,选择Delete(删除);

    3、右键设计器,并选择Add(新增)➤Entity(实体)。命名新实体为DeletedInvoice,并选择Invoice作为基类;

    4、在Mapping Details window(映射详细信息窗口),查看实体DeletedInvoice的映射信息。将它映射到Invoice表,在IsDeleted列上添加一个条件,When IsDeleted =1(当IsDeleted列值为1),如图6-22所示。

《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

图6-22 当IsDeleted列为1时映射DeletedInvoice实体

  包含Invoice实体和派生类型DeletedInvoice实体的最终模型,如图6-23所示。

《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

图6-23 包含实体Invoice和DeletedInvoice的概念模型

 原理

  有两种不同的方式可以对我们的Invoice和DeletedInvoice建模。我们演示的这种方法,只是在如下情况下推荐使用,你有一个已经存在的模型和代码库,你想添加派生类型实体DeletedInvoice, 并对已有代码产生尽量少的影响。对于一个新模型,从基类Invoice派生一个ActiveInvoice类型和一个DeleteInvoice类型会更好。如果选择后面这种方法,你需要将基类标记为抽象类型。

  这里使用我们演示的这种方式,正如代码清单6-37所展示的那样,你可以决定,是选择casting还是OfType<>()方法来转换DeletedInvoice。但是,你不能单独select实体Invoice,这是这个方法最大的缺点。

代码清单6-37.使用as操作符来判断我们拥有的是一个Invoice类型还是DeletedInvoice类型

  using (var context = new Recipe13Context())
{
context.Invoices.Add(new Invoice
{
Amount = 19.95M,
Description = "Oil Change",
Date = DateTime.Parse("4/11/13")
});
context.Invoices.Add(new Invoice
{
Amount = 129.95M,
Description = "Wheel Alignment",
Date = DateTime.Parse("4/01/13")
});
context.Invoices.Add(new DeletedInvoice
{
Amount = 39.95M,
Description = "Engine Diagnosis",
Date = DateTime.Parse("4/01/13")
});
context.SaveChanges();
} using (var context = new Recipe13Context())
{
foreach (var invoice in context.Invoices)
{
var isDeleted = invoice as DeletedInvoice;
Console.WriteLine("{0} Invoice",
isDeleted == null ? "Active" : "Deleted");
Console.WriteLine("Description: {0}", invoice.Description);
Console.WriteLine("Amount: {0:C}", invoice.Amount);
Console.WriteLine("Date: {0}", invoice.Date.ToShortDateString());
Console.WriteLine();
}
}

代码清单6-37的输出如下:

Active Invoice
Description: Oil Change
Amount: $19.95
Date: //
Active Invoice
Description: Wheel Alignment
Amount: $129.95
Date: //
Deleted Invoice
Description: Engine Diagnosis
Amount: $39.95
Date: //

6-14  创建独立关联和外键关联

问题

  你想使用Model First来创建独立关联和外键关联。

解决方案

  独立关联和外键关联帮助我们在数据库架构内维护引用完整性,并提供指向关联实体的导航路径。为了使用Model First创建外键和独立关联,请按下面的步骤操作:

    1、在你的项目中添加一新个ADO.NET Entity Data Model(ADO.NET实体数据模型),在提示选择模型内容时选择空模型,单击完成。这将创建一个空的计设界面;

    2、右键设计器,并选择Add(新增)➤Entity(实体)。命名新实体为User,并单击OK(确定);

    3、右键新添加的实体,为其添加一个标量属性UserName;

    4、右键设计器,并选择Add(新增)➤Entity(实体)。命名新实体为PassordHistory,并单击OK(确定);

    5、右键新添加的实体,为其添加一个标量属性LastLogin。右键LastLogin,改变其类型为DateTime;

    6、右键实体User,选择Add(增加) ➤Association(关联)。创建外键关联,勾选Add froreign key properties to the PasswordHistory Entity(向“PassordHistory”实体中添加外键属性)复选框; 创建独立关联,就不要勾选。

    7、右键设计器,并选择Generate Model from Database(从数据库生成模型)。选择一个数据库连接,并完成接下来的向导。这将产生模型的存储层和映射层,并生成一个从模型生成 数据库的脚本。

  如果你选择创建一个外键关联,模型如图6-24所示。如果选择创建一个独立关联,模型如图6-25所示。

《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

图6-24. User和PasswordHistory之间的外键关联

《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

图6-25. User和PasswordHistory之间的独立关联

原理

  对于一个外键关联,外键被当作依赖实体的一个属性。暴露外键允许使用与管理别的属性值相同的代码,来管理关联的很多方面。最主要的帮助就是在离线场景,我们将会在第九章看到相关的内容。外键关联是实体模型的默认行为。

  对于独立关联,外键不会作为依赖实体的属性。这使得模型的概念层有几分清爽,因为这里没有引入关联的实现细节这种噪音。在早期的实体框架版本中只支持独立关联。

6-15  修改独立关联为外键关联

问题

  你一个使用独立关联的模型,你想把独立关联改变成一个外键关联。

解决方案

  假设你有如图6-26所示的模型。

《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

图6-26. vehicles和tickets 间使用独立关联的模型

  按下面的步骤修改一个独立关联为外键关联:

    1、右键Ticket实体,选择Add(新增) ➤Scalar Property(标量属性)。并重命名为LicenseNumber(牌照号码);

    2、在Mapping Details window(映射详细信息窗口)中查看关联的映射信息,从映射到Ticket控件中选择 <Delete>,移除Ticket表的映射;

    3、右键关联,查看properties(属性),单击引用约束控制按钮,在弹出的对话框中,在Principal(主体)下拉菜单中选择Vehicle。Principal Key(主体键)和Dependent Property(依赖属性)均设置为LicenseNumber,如图6-27所示。

《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

图6-27. 为外键关联创建引用约束

    4、在Mapping Details window(映射详细信息窗口)中查看实体Ticket的映射信息,映射列LicenseNumber到属性LicenseNumber,如图6-28所示。

《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

图6-28. 为实体ticket映射LicenseNumber属性到LicenseNumber列

  最终的模型如图6-29所示。

《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

图6-29. 独立关联修改为外键关联的模型

原理

  当你把独立关联修改成外键关联后,你已存在的绝大多数代码是可以正常运行的。你会发现,现在关联两个实体变得非常简单了,只需给外键属性设置合适的值 。在独立关联中改变一个关系,你需要为实体键创建一个新的实例,并设置实体的xxxReference.EntityKey为这个新的实例。在外键关联中,你只需要简单地设置外键属性的值为主键值。

  外键关联目前不支持多对多关联,因为这些关联必须被映射到底层的链接表。也许,在将来的实体框架的版本中,外键关联,通过附带载荷来支持多对多关联。

  至此,第六章结束,下篇我们将进入第七章,本篇有点长,感谢你的阅读!

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

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