使用 @ManyToOne JPA 复合键用作 Id 来保存实体会添加额外的参数

问题描述 投票:0回答:1

类似于 @ManyToOne 在 JPA 中引用复合键。这是使用 Hibernate 5.6 的旧版本 Spring Boot。

我有三个实体类:

@Entity class A { Long getId(); ... }
@Entity class B { Long getId(); ... }

@Entity
@IdClass(ABPK.class)
@Data
class AB {
  @Id
  @Column(name="a_id", insertable=false, updatable=false)
  private Long aId;
  @Id
  @Column(name="b_id", insertable=false, updatable=false)
  private Long bId;
  @ManyToOne
  @JoinColumn(name="a_id")
  private A a;
  @ManyToOne
  @JoinColumn(name="b_id")
  private B b;
  public AB() { }
  public AB(A a, B b) {
    this.a = a;
    this.aId = a.getId();
    this.b = b;
    this.bId = b.getId();
  }
}

@Data
class ABPK implements Serializable {
  Long aId;
  Long bId;
}

当我尝试创建并保存它时

var a = new A("a");
var b = new B("b");
var ab = new AB(a,b);
abDao.saveAndFlush(ab);

我遇到了最奇怪的错误

原因:java.sql.SQLException:参数索引超出范围(3 > 参数数量,即 2)。

它生成的插入语句在日志中是正确的

Hibernate: insert into ab (a_id, b_id) values (?, ?)

我运行了调试器,当我只期待两个时,它似乎添加了第三个“字段”来映射,第一个似乎是

AB
类型,然后是
A
,然后是
B

java spring-boot hibernate
1个回答
0
投票

我用 Hibernate 5.6.15 重现了这个问题 - 尽管确切的版本并不重要,但我认为这是规范中的一个复杂区域,其细节通常被误解。无论如何,关系字段中的

@MapsId
为我解决了问题。即:

@Entity
@IdClass(ABPK.class)
@Data
class AB {
  @Id
  @Column(name="a_id", insertable=false, updatable=false)
  private Long aId;

  @Id
  @Column(name="b_id", insertable=false, updatable=false)
  private Long bId;

  @MapsId("aId")             // <--- HERE
  @ManyToOne
  @JoinColumn(name="a_id")
  private A a;

  @MapsId("bId")             // <--- AND HERE
  @ManyToOne
  @JoinColumn(name="b_id")
  private B b;

  public AB() { }

  public AB(A a, B b) {
    this.a = a;
    this.aId = a.getId();
    this.b = b;
    this.bId = b.getId();
  }
}

© www.soinside.com 2019 - 2024. All rights reserved.