EF6 秘籍 2th:实体数据建模基础 (十一)建模TPT(Table per Type)继承
问题描述:
假设有一些表用于保存公共表的额外信息,现在想使用TPT继承对其建模。
解决方案:
假定现在有2个表关联到一个公共表,如下图所示:
Business表和Retail表及eCommerce表间都是一个1对零个或1个的关系,其中Business表是1端。关键的特点是Retail表和eCommerce表扩展了Business表中business的信息。
Business表包含一些任何business都有的公共属性,Retail表和eCommerce表都同它紧密相连。为了建模一个TPT继承,也就是说Retail实体类型和eCommerce实体类型都继承于Business基实体类型,需要实现以下步骤:
1、生成一个派生自DbContext类的类,需要引入System.Data.Entity名称空间,添加默认构造函数,并调用父类的构造函数base("name=connectionStringName")。connectionStringName是EF框架的连接字符串名称,在配置文件中可以找到,没有的话需要手动添加或使用EDM向导的代码优先方式创建。并重写父类的OnModelCreating方法。
2、生成一个Business POCO 实体类型。
[Table("Business",Schema="Chapter2")]publicclassBusiness{[Key][DatabaseGenerated(DatabaseGeneratedOption.Identity)]publicintBusinessId{get;set;}publicstringName{get;set;}publicstringLicenseNumber{get;set;}}
3、生成一个eCommerce POCO 实体类型和Retail POCO 实体类型,它们都继承于Business POCO实体类型。
[Table("eCommerce",Schema="Chapter2")]publicclasseCommerce:Business{publicstringURL{get;set;}}[Table("Retail",Schema="Chapter2")]publicclassRetail:Business{publicstringAddress{get;set;}publicstringCity{get;set;}publicstringState{get;set;}publicstringZIPCode{get;set;}}
4、在DbContext子类中添加一个DbSet<Business>自动属性。
原理:
Retail表和eCommerce表是同Business表的1:0..1关系的0..1端。这意味着一个business实体可以没有任何额外的信息,也可以有额外的Retail信息或eCommerce信息。在OOP术语中,描述为一个基类型Business和2个派生类型Retail和eCommerce。
因为这是一个1:0..1的关系,所以在Retail表和eCommerce表中不存在这样的记录,它们在Business表中不存在相关的记录。在面向对象的术语中描述为,派生类的实例包含有基类的属性。派生类扩展基类属性的概念是继承的关键特性之一。在TPT继承中,每一个派生类都表示为一个单独的表。
using(varcontext=newEF6Recipes8Context()){varbusiness=newBusiness{Name="CornerDryCleaning",LicenseNumber="100x1"};context.Businesses.Add(business);varretail=newRetail{Name="ShopandSave",LicenseNumber="200C",Address="101Main",City="AnyTown",State="TX",ZIPCode="76106"};context.Businesses.Add(retail);varweb=neweCommerce{Name="BuyNow.com",LicenseNumber="300AB",URL="www.buynow.com"};context.Businesses.Add(web);context.SaveChanges();}using(varcontext=newEF6Recipes8Context()){Console.WriteLine("\n---AllBusiness---");foreach(varbincontext.Businesses){Console.WriteLine("{0}(#{1})",b.Name,b.LicenseNumber);}Console.WriteLine("\n---RetailBusiness---");foreach(varrincontext.Businesses.OfType<Retail>()){Console.WriteLine("{0}(#{1}",r.Name,r.LicenseNumber);Console.WriteLine("{0}",r.Address);Console.WriteLine("{0},{1}{2}",r.City,r.State,r.ZIPCode);}Console.WriteLine("\n---eCommerceBusiness---");foreach(vareincontext.Businesses.OfType<eCommerce>()){Console.WriteLine("{0}(#{1})",e.Name,e.LicenseNumber);Console.WriteLine("Onlineaddressis:{0}",e.URL);}}
上面的代码生成和实例化Business实体类型和2个派生类型,并使用context中的Business实体集合的Add()方法将其添加到context中。
在查询部分,为了访问所有的business实例,我们迭代整个business实体集合;为了获取派生类型,我们调用OfType方法过滤Business实体集合。
TPT是EF支持的3种继承模式中的一个。另外2个是TPH(Table per Hierarchy)和TPCT(Table per Concrete Type)。
TPT继承提供了很大的数据库灵活性,我们能够容易的添加表作为一个派生类型,并按照它们自己的方式添加到模型中。然而,每一个派生类型涉及额外的连接,这将导致性能下降。在实际的应用中,使用TPT时,我们已经看到显著的性能问题当一些派生类被建模时。
而TPH存储整个继承在单个表,它消除了TPT的连接,因此提供更好的性能,但更低的灵活性。
TPCT被EF运行时支持,而不是设计时。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。