Hibernate -从3.6升级到5.2后,ClassCastException检索带有JoinColumnOrFormula注解的实体

dzhpxtsq  于 2023-11-21  发布在  其他
关注(0)|答案(1)|浏览(180)

我们有以下数据模型(不重要的列省略):

TABLE_CONNECTION:
+--+
|ID|
+--+
|1 |
|2 |
+--+

TABLE_ENDPOINT:
+--+------+-------------+
|ID|CON_ID|ENDPOINT_TYPE|
+--+------+-------------+
|1 |1     |FROM         |
|2 |1     |TO           |
|3 |2     |FROM         |
|4 |2     |TO           |
+--+------+-------------+

字符串
该模型在Hibernate 3.6.10中的Map方式如下:

@Entity
@Table(name = "TABLE_CONNECTION")
@Immutable
public class Connection {

    @Id
    @Column(name = "ID", unique = true, nullable = false, precision = 38, scale = 0)
    private BigDecimal id;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumnsOrFormulas({
        @JoinColumnOrFormula(column = @JoinColumn(name = "ID", referencedColumnName = "CON_ID"))
        @JoinColumnOrFormula(formula = @JoinFormula(value = "'FROM'", referencedColumnName = "ENDPOINT_TYPE"))
    })
    private Endpoint fromEndpoint;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumnsOrFormulas({
        @JoinColumnOrFormula(column = @JoinColumn(name = "ID", referencedColumnName = "CON_ID"))
        @JoinColumnOrFormula(formula = @JoinFormula(value = "'TO'", referencedColumnName = "ENDPOINT_TYPE"))
    })
    private Endpoint toEndpoint;

    ...
}
@Entity
@Table(name = "TABLE_ENDPOINT")
@Immutable
public class Endpoint {

    @Id
    @Column(name = "ID", unique = true, nullable = false, precision = 38, scale = 0)
    private BigDecimal id;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "CON_ID", nullable = false)
    private Connection connectionId;

    @Column(name = "ENDPOINT_TYPE", length = 4, nullable = false)
    @Enumerated(EnumType.STRING)
    private EndpointType endpointType;

    ...
}

enum EndpointType {FROM, TO}

的数据
最近我们把Hibernate迁移到了5.2.18版本,简单调用hibernateTemplate.get(Connection.class, BigDecimal.valueOf(1))就会抛出异常:

java.lang.ClassCastException: com.our.package.Endpoint cannot be cast to java.math.BigDecimal

    at org.hibernate.type.descriptor.java.BigDecimalTypeDescriptor.extractHashCode(BigDecimalTypeDescriptor.java:19)
    at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:204)
    at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:209)
    at org.hibernate.engine.spi.EntityUniqueKey.generateHashCode(EntityUniqueKey.java:67)
    at org.hibernate.engine.spi.EntityUniqueKey.<init>(EntityUniqueKey.java:48)
    at org.hibernate.type.ManyToOneType.resolve(ManyToOneType.java:250)
    at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:171)
    at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:128)
    at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.performTwoPhaseLoad(AbstractRowReader.java:238)
    at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:209)
    at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:133)
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:122)
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:86)
    at org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader.load(AbstractLoadPlanBasedEntityLoader.java:185)
    at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4121)
    at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:508)
    at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:478)
    at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:219)
    at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:278)
    at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:121)
    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:89)
    at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1240)
    at org.hibernate.internal.SessionImpl.access$1900(SessionImpl.java:204)
    at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.doLoad(SessionImpl.java:2842)
    at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2816)
    at org.hibernate.internal.SessionImpl.get(SessionImpl.java:1076)
    at org.springframework.orm.hibernate5.HibernateTemplate.lambda$get$0(HibernateTemplate.java:456)
    at org.springframework.orm.hibernate5.HibernateTemplate.doExecute(HibernateTemplate.java:367)
    at org.springframework.orm.hibernate5.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:334)
    at org.springframework.orm.hibernate5.HibernateTemplate.get(HibernateTemplate.java:451)
    at org.springframework.orm.hibernate5.HibernateTemplate.get(HibernateTemplate.java:445)


你怎么了?

yrwegjxp

yrwegjxp1#

事实证明,升级版的Hibernate无法通过@JoinColumnAndFormula连接实体,其中实体本身是强实体(由自己的ID键标识)。由于实体实际上是弱实体(由(CON_ID, ENDPOINT_TYPE)元组充分标识),更改为多个@ Id注解列的复合标识符解决了这个问题:

@Entity
@Table(name = "TABLE_ENDPOINT")
@Immutable
public class Endpoint {

    @Column(name = "ID", unique = true, nullable = false, precision = 38, scale = 0)
    private BigDecimal id;

    @Id
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "CON_ID", nullable = false)
    private Connection connectionId;

    @Id
    @Column(name = "ENDPOINT_TYPE", length = 4, nullable = false)
    @Enumerated(EnumType.STRING)
    private EndpointType endpointType;

}

字符串
(Also Connection类中的@JoinColumnsOrFormulas是不必要的,因为@JoinColumnsOrFormula注解是@Repeatable。)

**更新:**替代解决方案(稍后发现):

Connection.fromEndpointConnection.toEndpoint字段上的@OneToOne注解更改为@ManyToOne(急切与否无关紧要)。

相关问题