0

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

最初,我什至无法编译它,因为 common.domain.Manufacturer 没有被识别为实体。我可以通过我的 ORM 配置定义实体映射来解决这个问题(有关更多详细信息,请参阅:处理映射超类中的休眠持久性)。虽然这确实解决了编译问题,但不幸的是我在运行时仍然看到错误。当我在映射的超类上调用 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 具有直接依赖关系。除非用尽所有其他可能性,否则我什至不会考虑。

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

4

1 回答 1

1

映射的超类不是实体。它只是一个与其子类共享其映射定义的类。因此,您不能使用 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 映射继承层次结构的不同选项,我建议您阅读我的深入指南:JPA 和 Hibernate 的继承策略 – 完整指南

于 2021-02-26T09:09:38.197 回答