In the previous blog post you saw that there are three different approaches to representing an inheritance hierarchy and I explained Table per Hierarchy (TPH) as the default mapping strategy in EF Code First. We argued that the disadvantages of TPH may be too serious for our design since it results in denormalized schemas that can become a major burden in the long run. In today’s blog post we are going to learn about Table per Type (TPT) as another inheritance mapping strategy and we'll see that TPT doesn’t expose us to this problem.

Table per Type (TPT)

Table per Type is about representing inheritance relationships as relational foreign key associations. Every class/subclass that declares persistent properties—including abstract classes—has its own table. The table for subclasses contains columns only for each noninherited property (each property declared by the subclass itself) along with a primary key that is also a foreign key of the base class table. This approach is shown in the following figure:

For example, if an instance of the CreditCard subclass is made persistent, the values of properties declared by the BillingDetail base class are persisted to a new row of the BillingDetails table. Only the values of properties declared by the subclass (i.e. CreditCard) are persisted to a new row of the CreditCards table. The two rows are linked together by their shared primary key value. Later, the subclass instance may be retrieved from the database by joining the subclass table with the base class table.

TPT Advantages

The primary advantage of this strategy is that the SQL schema is normalized. In addition, schema evolution is straightforward (modifying the base class or adding a new subclass is just a matter of modify/add one table). Integrity constraint definition are also straightforward (note how CardType in CreditCards table is now a non-nullable column).

Implement TPT in EF Code First

We can create a TPT mapping simply by placing Table attribute on the subclasses to specify the mapped table name (Table attribute is a new data annotation and has been added toSystem.ComponentModel.DataAnnotations namespace in CTP5):

public abstract class BillingDetail
{
public int BillingDetailId { get; set; }
public string Owner { get; set; }
public string Number { get; set; }
} [Table("BankAccounts")]
public class BankAccount : BillingDetail
{
public string BankName { get; set; }
public string Swift { get; set; }
} [Table("CreditCards")]
public class CreditCard : BillingDetail
{
public int CardType { get; set; }
public string ExpiryMonth { get; set; }
public string ExpiryYear { get; set; }
} public class InheritanceMappingContext : DbContext
{
public DbSet<BillingDetail> BillingDetails { get; set; }
}
If you prefer fluent API, then you can create a TPT mapping by using ToTable() method:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<BankAccount>().ToTable("BankAccounts");
modelBuilder.Entity<CreditCard>().ToTable("CreditCards");
}

Polymorphic Associations

polymorphic association is an association to a base class, hence to all classes in the hierarchy with dynamic resolution of the concrete class at runtime. For example, consider the BillingInfo property of User in the following domain model. It references one particular BillingDetail object, which at runtime can be any concrete instance of that class.

In fact, because BillingDetail is abstract, the association must refer to an instance of one of its subclasses only—CreditCard or BankAccount—at runtime.

Implement Polymorphic Associations with EF Code First

We don’t have to do anything special to enable polymorphic associations in EF Code First; The user needs a unidirectional association to some BillingDetails, which can be CreditCard or BankAccount so we just create this association and it would be naturally polymorphic:

public class User
{
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int BillingDetailId { get; set; } public virtual BillingDetail BillingInfo { get; set; }
}
In other words, as you can see above, a polymorphic association is an association that may refer instances of a subclass of the class that was explicitly specified as the type of the navigation property (e.g. User.BillingInfo).

The following code demonstrates the creation of an association to an instance of the CreditCard subclass:

using (var context = new InheritanceMappingContext())
{
CreditCard creditCard = new CreditCard()
{
Number = "",
CardType =
};
User user = new User()
{
UserId = ,
BillingInfo = creditCard
};
context.Users.Add(user);
context.SaveChanges();
}
Now, if we navigate the association in a second context, EF Code First automatically retrieves the CreditCard instance:
using (var context = new InheritanceMappingContext())
{
User user = context.Users.Find();
Debug.Assert(user.BillingInfo is CreditCard);
}

Polymorphic Associations with TPT

Another important advantage of TPT is the ability to handle polymorphic associations. In the database a polymorphic association to a particular base class will be represented as a foreign key referencing the table of that particular base class. (e.g. Users table has a foreign key that references BillingDetails table.)

Generated SQL For Queries

Let’s take an example of a simple non-polymorphic query that returns a list of all the BankAccounts:

var query = from b in context.BillingDetails.OfType<BankAccount>() select b;
Executing this query (by invoking ToList() method) results in the following SQL statements being sent to the database (on the bottom, you can also see the result of executing the generated query in SQL Server Management Studio):
Now, let’s take an example of a very simple polymorphic query that requests all the BillingDetails which includes both BankAccount and CreditCard types:
var query = from b in context.BillingDetails select b;
This LINQ query seems even more simple than the previous one but the resulting SQL query is not as simple as you might expect:
As you can see, EF Code First relies on an INNER JOIN to detect the existence (or absence) of rows in the subclass tables CreditCards and BankAccounts so it can determine the concrete subclass for a particular row of the BillingDetails table. Also the SQL CASE statements that you see in the beginning of the query is just to ensure columns that are irrelevant for a particular row have NULL values in the returning flattened table. (e.g. BankName for a row that represents a CreditCard type)

TPT Considerations

Even though this mapping strategy is deceptively simple, the experience shows that performance can be unacceptable for complex class hierarchies because queries always require a join across many tables. In addition, this mapping strategy is more difficult to implement by hand— even ad-hoc reporting is more complex. This is an important consideration if you plan to use handwritten SQL in your application (For ad hoc reporting, database views provide a way to offset the complexity of the TPT strategy. A view may be used to transform the table-per-type model into the much simpler table-per-hierarchy model.)

Summary

In this post we learned about Table per Type as the second inheritance mapping in our series. So far, the strategies we’ve discussed require extra consideration with regard to the SQL schema (e.g. in TPT, foreign keys are needed). This situation changes with the Table per Concrete Type (TPC) that we will discuss in the next post. 

原文地址:http://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-2-table-per-type-tpt

Inheritance with EF Code First: Part 2 – Table per Type (TPT)的更多相关文章

  1. Inheritance with EF Code First: Part 3 – Table per Concrete Type (TPC)

    Inheritance with EF Code First: Part 3 – Table per Concrete Type (TPC) This is the third (and last) ...

  2. Inheritance with EF Code First: Part 1 – Table per Hierarchy (TPH)

    以下三篇文章是Entity Framework Code-First系列中第七回:Entity Framework Code-First(7):Inheritance Strategy 提到的三篇.这 ...

  3. EF Code First学习系列

    EF Model First在实际工作中基本用不到,前段时间学了一下,大概的了解一下.现在开始学习Code First这种方式.这也是在实际工作中用到最多的方式. 下面先给出一些目录: 1.什么是Co ...

  4. 1.什么是Code First(EF Code First 系列)

    EF4.1中开始支持Code First .这种方式在领域设计模式中非常有用.使用Code First模式,你可以专注于领域设计,根据需要,为你一个领域的对象创建类集合,而不是首先来设计数据库,然后来 ...

  5. 从零开始,搭建博客系统MVC5+EF6搭建框架(1),EF Code frist、实现泛型数据仓储以及业务逻辑

    前言      从上篇30岁找份程序员的工作(伪程序员的独白),文章开始,我说过我要用我自学的技术,来搭建一个博客系统,也希望大家给点意见,另外我很感谢博客园的各位朋友们,对我那篇算是自我阶段总结文章 ...

  6. IoC容器Autofac - Autofac + Asp.net MVC + EF Code First(转载)

    转载地址:http://www.cnblogs.com/JustRun1983/archive/2013/03/28/2981645.html  有修改 Autofac通过Controller默认构造 ...

  7. MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等

    SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...

  8. EF Code First 学习笔记:表映射

    多个实体映射到一张表 Code First允许将多个实体映射到同一张表上,实体必须遵循如下规则: 实体必须是一对一关系 实体必须共享一个公共键 观察下面两个实体: public class Perso ...

  9. EF Code First一对一、一对多、多对多关联关系配置

    1.EF Code First一对一关联关系 项目结构图: 实体类: Account.cs using System; using System.Collections.Generic; using ...

随机推荐

  1. python_安装python2.7.7和easy_install

    [环境]: WIN7 + 32位 [要求]: 安装python2.7.7, easy_install 1. 下载并安装python2.7.7 首先访问http://www.python.org/dow ...

  2. zoj1967 poj2570 Fiber Network (floyd算法)

    虽然不是最短路,但是询问时任意两点之间的信息都要知道才能回答,由此联想到floyd算法,只要都floyd算法的原理理解清楚了就会发现:这道题的思想和求任意两点之间的最短路的一样的,只不过是更新的信息不 ...

  3. AJAX的最小单元

    $(function(){ $('#send').click(function(){ $.ajax({ type: "GET", url: "test.json" ...

  4. [BZOJ5251][多省联测2018]劈配

    bzoj luogu sol 从前往后依次加边,每次对一个人做完劈配后就把当前这个残余网络存下来.这样第二问就可以二分排在第几名然后check一下在对应排名的残余网络上还能不能再增广. 给网络流开结构 ...

  5. loopqueue

    import java.util.Arrays; public class loopQueue <E>{ public Object[] data=null; private int ma ...

  6. unity 查看打包资源占用

    想要压缩包大小,首先得知道打包出来的各个资源的大小,明确知道哪些资源占用大,可以通过如下操作打开Editor.log(可能需要先输出一遍安卓包) 1.在Unity Console界面右上角点开Open ...

  7. java流类基础练习。

    总结:BufferedReader.InputStreamReader.字节与字符的区别. package com.ds; import java.io.*; //从控制台输入字符串,输到sdd时停止 ...

  8. 分析诊断工具之五:Procedure Analyse优化表结构

    一.Procedure Analyse PROCEDURE ANALYSE() ,在优化表结构时可以辅助参考分析语句.通过分析select查询结果对现有的表的每一列给出优化的建议. 利用此语句,MyS ...

  9. 山区建小学(区间DP)

    山区建小学 时间限制: 1 Sec  内存限制: 128 MB提交: 17  解决: 5[提交][状态][讨论版][命题人:quanxing] 题目描述 政府在某山区修建了一条道路,恰好穿越总共m个村 ...

  10. MySQL脚本自动安装mysql-5.6.15-linux-glibc2.5-x86_64.tar.gz

    脚本安装mysql-5.6.15-linux-glibc2.5-x86_64.tar.gz 先准备好数据文件的路径 softdir='/data/soft' 把脚本和tar包放在相应的路径下,其实就是 ...