JPA: 实现模型层次结构 - @MappedSuperclass与@Inheritance的区别

75
我使用带有PostgreSQLJPA的Play Framework 1.2.4。 我想要一个模型层次结构,并且看到有一些替代方法可以实现这一点。
我有一个基类(是抽象的),以及两个扩展此基类的具体类。 我不想持久化此基类,而是想要具体类。 在基类中,我有另一个模型类作为属性,换句话说,我的基类中有@ManyToOne关系。
我的问题是实现这一点的最佳方法是什么? 使用@MappedSuperclass还是@InheritanceTABLE_PER_CLASS策略? 我有点困惑,因为它们似乎在本质上是等效的。
我还担心将来可能会遇到查询和性能问题。

3
我已将@Inheritence更改为@Inheritance,因为我认为这是一个打字错误。 - Cœur
2个回答

167

MappedSuperClass必须用于继承属性、关联和方法。

当您拥有一个实体以及几个子实体时,必须使用实体继承。

您可以通过回答以下问题来确定需不需要使用实体继承或MappedSuperClass:在模型中是否存在其他实体可能与基类存在关联?

如果是,则基类实际上是一个实体,应该使用实体继承。如果不是,则基类实际上是包含多个不相关实体的公共属性和方法的类,应该使用MappedSuperClass。

例如:

  • 您可以有几种消息类型:短信、电子邮件或电话消息。一个人有一些消息列表。您还可以将提醒与消息相关联,而不管消息的类型如何。在这种情况下,Message显然是一个实体,必须使用实体继承。
  • 所有域对象都可以具有创建日期、修改日期和ID,并且因此可以从一个基本的AbstractDomainObject类中继承。但是,没有任何实体会与AbstractDomainObject产生关联。它总是与更具体的实体(客户、公司等)相关联。在这种情况下,使用MappedSuperClass是有意义的。

非常感谢你的回答。我现在明确了如果我需要持久化或使用基类作为实体,我应该使用实体继承。我想知道在使用继承对象关系时是否存在性能问题或查询限制? - huzeyfe
这完全取决于您选择哪种继承方式和继承策略。 - JB Nizet
在我的情况下(因为我不想保留基类),MappedSuperClass 似乎更合适。因此,就性能和限制而言,我需要注意某些特定的问题吗? - huzeyfe
4
不会,它的工作方式与将映射的超类属性直接放在实体中一样。 - JB Nizet

39

@MappedSupperclass注解与@Inheritance注解不同。

@MappedSuperclass告诉JPA提供者将基类的持久属性包含在子类中,就好像它们是由使用@MappedSuperclass注解的超类扩展声明的一样。

然而,这种继承只在面向对象编程(OOP)的世界中可见,因为从数据库的角度来看,没有基类的指示。只有子类实体将具有关联的映射表。

@Inheritance注解旨在将面向对象的继承模型实现到数据库表结构中。此外,您可以查询使用@Inheritance注解的基类,但无法对使用@MappedSupperclass注解的基类进行查询。

现在,您想要使用@Inheritance JPA注解的原因是实现行为驱动模式,例如策略模式。

另一方面,@MappedSupperclass只是一种重用基本属性、关联甚至实体@Id的常见基类的方式。然而,您几乎可以使用@Embeddable类型实现相同的目标。唯一的主要区别是您无法使用@Embeddable重新使用@Id定义,但您可以使用@MappedSupperclass来实现。


4
唯一的主要区别在于,在使用Embeddable时,您不能重用Id定义,但是在使用MappedSuperclass时可以这样做。非常感谢,我已经试了将近一个小时才找到这个答案。 - Bahattin Ungormus
'@Inheritance' 的好处在于我们可以使用多态查询。将 '@Inheritance' 设置为 TABLE_PER_CLASS,与 '@MappedSuperclass' 有什么区别? - Serafins
1
TABLE_PER_CLASS非常低效,因为它使用UNION ALL查询。最好使用SINGLE_TABLE或JOINED,如我在高性能Java持久化书籍中所解释的那样。 - Vlad Mihalcea
谢谢,这让事情更清晰了。 - Julio Faerman
@JulioFaerman 我很高兴能够帮助。 - Vlad Mihalcea
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接