具有多重继承的实体框架TPC

时间:2012-02-23 09:29:22

标签: entity-framework

我正在使用EF与TPC,我有一个多重继承让我说我有

员工(摘要)

开发人员(继承自员工)

SeniorDeveloper(继承自开发人员)

我在数据库中插入了一些行,EF正确读取它们。

BUT 当我插入一个新的SeniorDeveloper时,值将被写入SeniorDeveloper AND Developer数据库表,因此只查询开发人员(context.Employees.OfType())也会获得最近添加的SeniorDevelopers。

有没有办法告诉EF,它应该只存储在一个表中,或者为什么EF会回归到TPT策略?

2 个答案:

答案 0 :(得分:1)

由于看起来EF不支持TPC的多重继承,我们最终使用TPC for Employee to Developer和TPT在Developer和SeniorDeveloper之间......

答案 1 :(得分:1)

我相信这是有原因的,虽然我可能看不到全貌,可能只是猜测。

情况

实际上,EF只能通过只读取Developer表在TPT场景中列出非高级开发人员(您的查询用例)的唯一方法(我看到)使用鉴别器,我们知道EF在TPT / TPC策略中没有使用它。

为什么呢?好吧,请记住,所有高级开发人员都是开发人员,因此他们拥有Developer记录以及SeniorDeveloper记录是自然的(也是必要的)。

唯一的例外是如果Developer是抽象类型,在这种情况下,您可以使用TPC策略完全删除Developer表。但是,在您的情况下,Developer是具体的。

当前解决方案

记住这一点,并且在Developer表中没有鉴别器,确定任何开发人员是否为非高级开发人员的唯一方法是检查是否高级开发人员;换句话说,通过验证SeniorDeveloper表或任何其他子类型表中没有开发人员的记录。

这听起来有点明显,但现在我们理解为什么必须使用和访问它的基类型(Developer)是具体的(非抽象的)时才能使用和访问它。

当前的实施

我是从记忆中写下来的,所以我希望它不会太过分,但这也是Slauma在另一条评论中提到的。您可能想要启动SQL事件探查器并验证这一点。

它的实现方式是通过请求表的投影的UNION。这些投影只是添加一个鉴别器,以某种编码方式声明它们自己的类型[1]。在联合集中,然后可以基于此鉴别器过滤行。

[1]如果我没记错的话,它会是这样的:基本类型为0X,联合中第一个子类型为0X0X,第二个子类型为0X1X,依此类推。 < / p>

权衡#1

我们已经可以确定一个权衡:EF可以在表格中存储一个鉴别器,或者它可以生成一个&#34;在&#34;运行时间&#34;。

  • 存储的鉴别器的缺点是它的空间效率较低,并且可能是“丑陋的”。 (如果这是一个论点)。优点是查找性能在非常具体的情况下(我们只需要 base 类型的记录)。
  • &#34;运行时间&#34;的缺点鉴别器是查找性能不如同一个用例好。优点是它更节省空间。
乍一看,似乎有时候我们可能更喜欢用一点空间来换取查询性能,但EF不会让我们这么做。

实际上,它并不总是很清楚;通过请求两个表的UNION,我们只查找两个索引而不是一个,性能差异可以忽略不计。使用单一级别的继承,它不会比2x差(因为所有子类型集都是不相交的)。但等等,还有更多。

权衡#2

请记住,我说存储鉴别器方法的性能优势只会出现在我们查找基类型记录的特定用例中。那是为什么?

好吧,如果您正在寻找可能是也可能不是高级开发人员的开发人员[2],那么您仍然被迫查找SeniorDeveloper 。虽然这看起来很明显,但可能不那么明显的是,如果类型只是一种类型或另一种类型,EF不能事先知道。这意味着它必须在最坏的情况下发出两个查询:一个在Developer表上,如果结果集中甚至有一个高级开发人员,则第二个在SeniorDeveloper表。

不幸的是,额外的往返可能比两个表中的UNION具有更大的性能影响。 (我可能会说,我还没有验证过它。)更糟糕的是,对于结果集中有一行的每个子类型,它会增加。想象一下具有3种,5种甚至10种亚型的类型。

那是你的权衡#2。

[2]请记住,这种操作可能来自您的应用程序的任何部分,而解决权衡必须全局完成以满足所有进程/应用程序/用户。还要考虑到EF团队必须为所有EF用户进行权衡(尽管他们可以为这些类型的权衡添加一些配置)。

可能的替代方案

通过批处理SQL查询,可以避免多次往返。 EF必须向服务器发送一些过程逻辑以进行条件查找(T-SQL)。但是,由于我们已经在权衡#1中建立了性能优势在很多情况下很可能忽略不计,我不确定这是否值得付出努力。也许有人可以为此打开发票,以确定它是否有意义。

<强>结论

将来,也许有人可以通过一些创造性的解决方案优化这个特定场景中的一些典型操作,然后在优化涉及这些权衡时提供一些配置开关。

但是现在,我认为EF选择了一个公平的解决方案。以一种奇怪的方式,它几乎更清洁。

一些注释

  • 我认为联合的使用是在某些情况下应用的优化。在其他情况下,它将是一个外部联接,但使用鉴别器(以及其他所有内容)保持不变。

  • 你提到了多重继承,这有点让我困惑。在通用的面向对象的说法中,多继承是一种类型具有多种基类型的构造。许多面向对象的类型系统都不支持这一点,包括CTS(所有.NET语言都使用)。你的意思是其他的东西。

  • 您还提到EF会退回&#34; TPT战略。对于Developer / SeniorDeveloper,TPC策略与TPT策略具有相同的结果,因为Developer是具体的。如果您真的想要一个表,那么必须使用TPH策略。