继承选择策略,一下是一些经验法则:
- 如果你不需要多态关联或者查询,就倾向于每个具体类一张表——换句话说,如果你从不或者很少查询BillingDetails,并且没有关联BillingDetails的类。基于UNION的显式映射应该是首选,因为随后(最优化的)多态查询和关联将成为可能。隐式多态对于利用非持久化相关的接口的查询最有用。
- 如果你一定要多态关联(对超类的关联,及由此在运行时通过具体类的动态解析对层次结构中所有类的关联)或者查询,并且子类相对地声明几种属性(尤其当子类之间的主要区别在于它们的行为中)时,则倾向于每个类层次结构一张表。你的目标是把可为空的列数减到最少,并让你自己(和数据库管理员)确信反规范化的Schema在长期运行中不会产生问题。
- 如果你一定需要多态的关联或者查询,并且子类声明多个属性(子类的不同主要在于它们所持有的数据),则倾向每个子类一张表。或者,根据继承层次结构的宽度和深度,以及想对于联合的可能联结成本,使每个具体类一张表。
默认情况下,仅对简单的问题选择每个类层次结构一张表。对于更复杂的案例(或者当你被一位坚持认为可为空的能力约束和标准化很重要的数据建模者否决的时候),就应该考虑每个子类一张表的策略。但这时候要问问自己:在对象模型中,重新把继承建模为委托是否未必更好。对于无关持久化或者ORM的各种原因,通常最好避免复杂的继承。Hibernate充当着领域和关系模型之间的缓冲区,但这并不意味着在设计类的时候,可以忽略持久化关注点。
当你开始考虑混合的继承策略时,记住:HIbernate中的隐式多态很聪明,足以处理更多异乎寻常的情况。例如,在考虑在应用程序中增加一个接口ElectronicPaymentOption。这是一个没有持久化方面的业务接口——除了在我们的应用程序中,例如CreditCard这样的持久化类将可能实现这个接口之外。无论你如何映射BillingDetails层次结构,Hibernate都可以正确地给from ElectronicPaymentOption回复查询。甚至不是BillingDetails层次结构一部分的其他类也可以,它们被映射为持久化,并实现这个接口。Hibernate始终知道要查询哪些表、构造哪些实例,以及如何返回一个多态的结果。
最后,也可以在单个的映射文件中使用<union-subclass>、<subclass>、和<joined-subclass>映射元素(作为一级元素,而不是<class>)。然后必须声明被扩展的类,例如<subclass name="CreditCard" extends="BillingDetails">,且必须在子类映射文件之前程序化地加载其类映射(在XML配置文件中列出映射资源清单时,不必担心这个顺序)。这种技术允许扩展类层次结构,而不用修改超类的映射文件。