Inheritance with EF Code First: Part 2 – Table per Type (TPT)
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 AdvantagesThe 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 FirstWe 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 |
If you prefer fluent API, then you can create a TPT mapping by using ToTable() method: |
protected override void OnModelCreating(DbModelBuilder modelBuilder) |
Polymorphic AssociationsA 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 FirstWe 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 |
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()) |
Now, if we navigate the association in a second context, EF Code First automatically retrieves the CreditCard instance: |
using (var context = new InheritanceMappingContext()) |
Polymorphic Associations with TPTAnother 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 QueriesLet’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 ConsiderationsEven 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.) |
SummaryIn 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)的更多相关文章
- 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) ...
- Inheritance with EF Code First: Part 1 – Table per Hierarchy (TPH)
以下三篇文章是Entity Framework Code-First系列中第七回:Entity Framework Code-First(7):Inheritance Strategy 提到的三篇.这 ...
- EF Code First学习系列
EF Model First在实际工作中基本用不到,前段时间学了一下,大概的了解一下.现在开始学习Code First这种方式.这也是在实际工作中用到最多的方式. 下面先给出一些目录: 1.什么是Co ...
- 1.什么是Code First(EF Code First 系列)
EF4.1中开始支持Code First .这种方式在领域设计模式中非常有用.使用Code First模式,你可以专注于领域设计,根据需要,为你一个领域的对象创建类集合,而不是首先来设计数据库,然后来 ...
- 从零开始,搭建博客系统MVC5+EF6搭建框架(1),EF Code frist、实现泛型数据仓储以及业务逻辑
前言 从上篇30岁找份程序员的工作(伪程序员的独白),文章开始,我说过我要用我自学的技术,来搭建一个博客系统,也希望大家给点意见,另外我很感谢博客园的各位朋友们,对我那篇算是自我阶段总结文章 ...
- IoC容器Autofac - Autofac + Asp.net MVC + EF Code First(转载)
转载地址:http://www.cnblogs.com/JustRun1983/archive/2013/03/28/2981645.html 有修改 Autofac通过Controller默认构造 ...
- MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等
SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管 ...
- EF Code First 学习笔记:表映射
多个实体映射到一张表 Code First允许将多个实体映射到同一张表上,实体必须遵循如下规则: 实体必须是一对一关系 实体必须共享一个公共键 观察下面两个实体: public class Perso ...
- EF Code First一对一、一对多、多对多关联关系配置
1.EF Code First一对一关联关系 项目结构图: 实体类: Account.cs using System; using System.Collections.Generic; using ...
随机推荐
- Codeforces Round #281 (Div. 2) A. Vasya and Football(模拟)
简单题,却犯了两个错误导致WA了多次. 第一是程序容错性不好,没有考虑到输入数据中可能给实际已经罚下场的人再来牌,这种情况在system测试数据里是有的... 二是chronologically这个词 ...
- 程序员如何编写好开发技术文档 如何编写优质的API文档工作
编写技术文档,是令众多开发者望而生畏的任务之一.它本身是一件费时费力才能做好的工作.可是大多数时候,人们却总是想抄抄捷径,这样做的结果往往非常令人遗憾的,因为优质的技术文档是决定你的项目是否引人关注的 ...
- OpenCV教程【002 VideoCapture加载并播放视频】
#include <opencv2/opencv.hpp> #include <iostream> using namespace std; using namespace c ...
- PKUSC2018 Slay The Spire
有攻击牌和强化牌各 $n$ 张,强化牌可以让之后所有攻击牌攻击力乘一个大于 $1$ 的系数,攻击牌可以造成伤害 求所有“抽出 $m$ 张然后打 $k$ 张”能造成的伤害之和 $k,m,2n \leq ...
- LeetCode 361. Bomb Enemy
原题链接在这里:https://leetcode.com/problems/bomb-enemy/description/ 题目: Given a 2D grid, each cell is eith ...
- WebSphere & Log4j
IBM的东西,真是太麻烦了,一个日志都给你替换掉,太霸道了,Google了下,居然是个普遍想象,不过也有相关的解决方 案,基本好像都是在 WAS5,WAS6.1上的,我没环境,不过我这边的WAS7 没 ...
- CAS单点登录系统简介
一.cas简介 全名:Central Authentication Service特点: 1.开源的.多协议的 SSO 解决方案: Protocols : Custom Protocol . CAS ...
- docker容器的服务发现:consul
官网:https://www.consul.io 官网文档:https://www.consul.io/docs简介 consul是一个服务发现的组件,在docker世界中他比较流行,主要是consu ...
- BZOJ3296:[USACO2011OPEN]Learning Language
浅谈并查集:https://www.cnblogs.com/AKMer/p/10360090.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php? ...
- mysql函数之三:find_in_set() 函数 返回str在字符串集strlist中的序号
如果字符串str是在的strlist组成的N子串的字符串列表,返回值的范围为1到N. FIND_IN_SET(str,strlist) 如果字符串str是在的strlist组成的N子串的字符串列表,返 ...