You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Hibernate Reactive持久化复合ID时出现字段访问错误

问题分析与解决方案

错误栈的核心信息显示:Can not set java.lang.String field myPackage.MyTableEntity.code2 to myPackage.MyTableEntity,说明Hibernate在处理复合ID的反射逻辑时,错误地将实体对象本身赋值给了code2字段(String类型),导致类型不匹配异常。结合你的代码场景,以下是针对性的解决方案:


1. 调整实体类ID字段的顺序与连续性

Hibernate处理@IdClass时,会按照ID类中字段的顺序匹配实体类的ID字段。如果实体类中ID字段被非ID字段打断,可能引发反射字段匹配错误。将非ID字段num移到所有ID字段之后:

@Table(name = "MY_TABLE")
@Entity
@IdClass(MyTableId.class)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MyTableEntity {

    @Id
    @Column(name = "CODE_1")
    private String code1;

    @Id
    @Column(name = "CODE_2")
    private String code2;

    @Id
    @Column(name = "DATE")
    private LocalDateTime date;

    @Column(name = "NUM")
    private Long num;
}

2. 显式在事务上下文执行持久化操作

Hibernate Reactive的持久化操作需要在事务中完成,虽然部分场景下withSession能工作,但显式使用withTransaction可以避免上下文缺失导致的异常:

@Repository
@AllArgsConstructor
public class MyTableRepository {

    private Stage.SessionFactory sessionFactory;

    public Mono<Void> save(MyTableEntity myTableEntity) {
        return Mono.fromCompletionStage(
                sessionFactory.withTransaction((session, transaction) -> 
                    session.persist(myTableEntity)
                )
        );
    }

    // 其他查询方法...
}

3. 移除Lombok注解,手动实现核心方法

Lombok生成的@Data可能与Hibernate的反射逻辑存在冲突,手动实现getter/setter、equals和hashCode(仅基于ID字段)可以排除此类问题:

实体类手动实现

import jakarta.persistence.*;
import java.time.LocalDateTime;
import java.util.Objects;

@Table(name = "MY_TABLE")
@Entity
@IdClass(MyTableId.class)
public class MyTableEntity {

    @Id
    @Column(name = "CODE_1")
    private String code1;

    @Id
    @Column(name = "CODE_2")
    private String code2;

    @Id
    @Column(name = "DATE")
    private LocalDateTime date;

    @Column(name = "NUM")
    private Long num;

    // 无参、全参构造方法
    public MyTableEntity() {}
    public MyTableEntity(String code1, String code2, LocalDateTime date, Long num) {
        this.code1 = code1;
        this.code2 = code2;
        this.date = date;
        this.num = num;
    }

    // getter/setter
    public String getCode1() { return code1; }
    public void setCode1(String code1) { this.code1 = code1; }
    public String getCode2() { return code2; }
    public void setCode2(String code2) { this.code2 = code2; }
    public LocalDateTime getDate() { return date; }
    public void setDate(LocalDateTime date) { this.date = date; }
    public Long getNum() { return num; }
    public void setNum(Long num) { this.num = num; }

    // equals/hashCode仅基于ID字段
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyTableEntity that = (MyTableEntity) o;
        return Objects.equals(code1, that.code1) &&
                Objects.equals(code2, that.code2) &&
                Objects.equals(date, that.date);
    }

    @Override
    public int hashCode() {
        return Objects.hash(code1, code2, date);
    }
}

复合ID类手动实现

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Objects;

public class MyTableId implements Serializable {
    private String code1;
    private String code2;
    private LocalDateTime date;

    public MyTableId() {}
    public MyTableId(String code1, String code2, LocalDateTime date) {
        this.code1 = code1;
        this.code2 = code2;
        this.date = date;
    }

    // getter/setter
    public String getCode1() { return code1; }
    public void setCode1(String code1) { this.code1 = code1; }
    public String getCode2() { return code2; }
    public void setCode2(String code2) { this.code2 = code2; }
    public LocalDateTime getDate() { return date; }
    public void setDate(LocalDateTime date) { this.date = date; }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyTableId myTableId = (MyTableId) o;
        return Objects.equals(code1, myTableId.code1) &&
                Objects.equals(code2, myTableId.code2) &&
                Objects.equals(date, myTableId.date);
    }

    @Override
    public int hashCode() {
        return Objects.hash(code1, code2, date);
    }
}

4. 升级Hibernate Reactive版本

你使用的2.0.6.Final版本存在部分@IdClass相关的已知bug,升级到最新的2.x稳定版本(如2.2.0.Final)可以修复此类问题。


内容的提问来源于stack exchange,提问作者MiKa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 16:34:53