当前位置: 首页 > 知识库问答 >
问题:

用于自定义鉴别器的Hibernate

澹台华晖
2023-03-14

我有一个具体的JPA实体超类,它使用鉴别器列与inheritanceType.joined映射,还有两个子类实体,它们用其他属性扩展了这个超类。

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "TYPE")
public class BaseEntity {
    // . . .
}

@Entity
@DiscriminatorValue("SUBTYPE")
public class SubclassEntity extends BaseEntity {
    // . . .
}

在某些情况下,我希望指定额外的鉴别器值,而不必为每个类型显式定义子类(也就是说,并不是每个“baseEntity”都指定支持子类/单独表的额外属性)。这种策略在数据库设计和Java类层次结构中都很有效,但是,Hibernate JPA不允许这样做,并抛出UrtranClassException,因为没有映射到鉴别器的子类:

Caused by: org.hibernate.WrongClassException: Object [id=entity-1] was not of the specified subclass [com.so.jpa.BaseEntity] : Discriminator: custom-1
    at org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl.getConcreteEntityTypeName(EntityReferenceInitializerImpl.java:415)
    at org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl.hydrateEntityState(EntityReferenceInitializerImpl.java:217)
    at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.readRow(AbstractRowReader.java:90)
    at org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails$EntityLoaderRowReader.readRow(EntityLoadQueryDetails.java:238)
    at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:112)
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:121)
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:85)
    at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:167)
    at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3954)
    at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:488)
    at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:453)
    at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:196)
    at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:258)
    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:134)
    at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1071)
    at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:990)
    at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:632)
    at org.hibernate.type.EntityType.resolve(EntityType.java:424)
    at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:154)
    at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:128)
    at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1132)
    at org.hibernate.loader.Loader.processResultSet(Loader.java:992)
    at org.hibernate.loader.Loader.doQuery(Loader.java:930)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:336)
    at org.hibernate.loader.Loader.doList(Loader.java:2611)
    at org.hibernate.loader.Loader.doList(Loader.java:2594)
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2423)
    at org.hibernate.loader.Loader.list(Loader.java:2418)
    at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:501)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:371)
    at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:220)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1268)
    at org.hibernate.internal.QueryImpl.list(QueryImpl.java:87)
    at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:567)
    at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:436)
    ...

在本例中,我希望Hibernate返回具体的基实体baseEntity,而不是尝试实例化子类。我在JPA规范(JSR338)中没有看到任何东西表明这不应该是可能的(尽管规范也没有明确地调用这个场景)。

共有1个答案

阎经武
2023-03-14

不幸的是,Hibernate只期望每个实体类型有一个鉴别器值。我想这与其他JPA提供程序没有区别,因为不能为一个实体类定义多个DiscriminatorValue

即使没有定义DiscriminatorValue,也会有一个:

如果未指定DiscriminatorValue注释并使用了discriminator列,则将使用特定于提供程序的函数生成表示实体类型的值。如果DiscriminatorTypeString,则discriminator值默认值是实体名称。

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorFormula(
    "CASE WHEN TYPE IN ('SUBTYPE', 'SUBTYPE-2', ...) THEN TYPE ELSE 'BaseEntity'")
public class BaseEntity {
    // . . .
}

@Entity
@DiscriminatorValue("SUBTYPE")
public class SubclassEntity extends BaseEntity {
    // ...
}
 类似资料:
  • Discriminator 是一种 schema 继承机制。 他允许你在相同的底层 MongoDB collection 上 使用部分重叠的 schema 建立多个 model。 假设你要在单个 collection 中记录多种 event, 每个 event 都有时间戳字段,但是 click 事件还有 URL 字段, 这时你可以用 model.discriminator() 实现上述要求。 此函

  • 我已经在web上阅读了几篇关于多租户(针对SaaS应用程序中的不同客户端)的文章(即这个和那个)。一旦您决定采用基于鉴别器的方法,hibernate文档声明,版本4不支持这种方法,但将在版本5中提供。 尽管如此,您可能会找到几篇关于为此目的使用hibernate过滤器的文章(即这篇和那篇)。 我想知道,如果基于过滤器的解决方案可以的话,为什么在版本5中会有一些特殊的实现呢。因此:基于过滤器的解决方

  • 我正在尝试为产品名称及其型号构建一个自定义命名实体提取器。 我的用例包含这样的句子:“微软使用了ABC-300产品,并将其与ASQ集成”。上述句子中提到的产品是:ABC-300和ASQ 我已经尝试使用Stanford和Spacy NER,两者的准确性都低于预期。 是否有任何数据集包含段落或句子中的产品名称,我可以用于训练自定义NER模型?训练的句子可以简单也可以复杂。任何类型的数据都很有用。 关于

  • 问题内容: 是否可以强制休眠将歧视符列用于继承的继承类型?根据JPA2.0规范,这应该可行,但是我无法在休眠状态下实现。 例: 使用hibernate.hbm2ddl.auto create时,这甚至都不会在表PARENT中创建列TYPE。 我知道InheritanceType.JOINED可以在不定义鉴别符列的情况下工作,但是它是非常无效的,因为在使用鉴别符列中的信息时,休眠需要在父对象和所有子

  • null 如何实现:Spring Data JPA不支持全局筛选器,所以我需要添加定制Spring Data JPA存储库,该存储库可以反过来为基于鉴别器的解决方案应用全局筛选器? 到底有没有可能用Spring Data JPA+Hibernate 3实现我的需求?

  • 我注意到Spring Boot执行器只有在应用程序使用Spring MVC(DispatcherServlet)处理endpoint时才起作用。默认情况下,如果您在项目中添加了spring-boot-starter-web模块,则包含此servlet。 一旦这个servlet存在,类EndpointWebMvcAutoConfiguration将定制Spring MVC,以支持endpoint和其