使用 Hibernate EntityManager 获取映射超类的实例

问题描述

我在处理 Hibernate 中的映射超类时遇到了一些问题。我有两个应用程序,产品和制造商,它们共享一个公共库,但彼此之间没有任何直接依赖关系。 Common lib 有一个抽象的 MappedSuperclass (common.domain.Manufacturer),它是基本实体。制造商有一个具体的类,它扩展了 Common 中的类。 Product 中没有该类的具体版本。

最初,我什至无法编译它,因为 common.domain.Manufacturer 未被识别为实体。我能够通过我的 ORM 配置定义实体映射来解决这个问题(有关更多详细信息,请参阅:Handling Hibernate Persistence in Mapped Superclass)。虽然这确实解决了编译问题,但不幸的是我仍然在运行时看到错误。当我在映射的超类上调用 entityManager.find() 时,它失败并显示错误org.hibernate.InstantiationException: Cannot instantiate abstract class or interface: : com.tura.common.domain.Manufacturer

我想也许我可以使用 entityManager.getReference() 而不是 find()。只要我实际上不需要关于除主键之外的制造商的任何信息,这就会起作用。不幸的是,代码中有几个地方我需要一些关于制造商的额外信息。只要我访问 Id 以外的任何字段,它就会失败并出现相同的错误

我现在可以看到三个选项,但它们都有我想避免的缺点。我可以使类的 Common 版本具体化,但这首先会破坏拥有此层次结构的目的。我不希望通用版本被实例化并可能被持久化。只有制造商应用程序应该这样做。我可以在 Product 应用程序中创建一个具体的类,但这需要向数据库添加一个 DTYPE,这在休眠之外毫无意义。最后也是最糟糕的选择是让 Product 和 Manufacturer 直接依赖。除非用尽所有其他可能性,否则我什至不会考虑这一点。

我觉得必须有一些干净的方式来做我需要的事情。任何帮助将不胜感激。

解决方法

mapped superclass 不是实体。它只是一个与其子类共享其映射定义的类。因此,您无法使用 Hibernate 或任何其他 JPA 实现来选择它。

如果您想在查询中选择超类或定义多态关联,您应该查看 table per class strategy。它将每个具体实体类映射到其自己的数据库表。您可以通过使用 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 注释您的超类来设置该策略,例如:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Manufacturer { ... }


@Entity
public class Product extends Manufacturer { ...}

下一步,你需要决定你的超类是否应该是抽象的。使用每个类的表策略,您可以使您的超类抽象。然后,您将无法实例化和持久化该类的任何对象。但是您可以在查询和关联映射中使用它们。 Hibernate 然后总是返回特定的子类。

您写道,您希望将超类抽象化,而在您的应用程序之一中没有任何具体的子类。这听起来像是一个有问题的设计决策,因为您将无法在该应用程序中使用超类。 Hibernate 不知道任何子类,您将无法选择或保留它们。

如果您想详细了解 JPA 映射继承层次结构的不同选项,我建议您阅读我的深入指南:Inheritance Strategies with JPA and Hibernate – The Complete Guide

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...