【问题标题】:Getting An Instance Of A Mapped Superclass With Hibernate EntityManager使用 Hibernate EntityManager 获取映射超类的实例
【发布时间】:2021-02-25 19:52:41
【问题描述】:

我在处理 Hibernate 中的映射超类时遇到了一些问题。我有两个应用程序,产品和制造商,它们共享一个公共库,但彼此之间没有任何直接依赖关系。 Common lib 有一个抽象的 MappedSuperclass (common.domain.Manufacturer),它是基础实体。制造商有一个扩展通用类的具体类。 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 具有直接依赖关系。除非用尽所有其他可能性,否则我什至不会考虑。

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

【问题讨论】:

    标签: java hibernate wildfly hibernate-entitymanager mappedsuperclass


    【解决方案1】:

    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

    【讨论】:

    • 不幸的是,table_per_class 与添加 DTYPE 有相同的问题。只有一张“制造商”表。产品不需要能够持久化制造商。它需要了解此类的唯一原因是建立与 Product 类的关联。
    • 当然,“制造商”表只有 1 个。您不能有 2 个具有相同名称的数据库表,并且只有 1 个实体类映射到该表。如果您的第二个模块/应用程序将使用制造商执行任何读取或写入操作,您不能将其抽象化。
    猜你喜欢
    • 2011-01-01
    • 2014-09-06
    • 1970-01-01
    • 1970-01-01
    • 2015-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    相关资源
    最近更新 更多