如何正确映射与@IdClass 的多对一关系?

Posted

技术标签:

【中文标题】如何正确映射与@IdClass 的多对一关系?【英文标题】:How to map properly a many-to-one relationship with @IdClass? 【发布时间】:2018-09-17 16:00:40 【问题描述】:

我想在 Hibernate 中使用组合主键创建一个表。主键的一部分是自动生成的值,另一部分以多对一的关系引用另一个表的主键。

我没有使用@EmbeddedId,因为我没有设法使@Embeddable 类中的自动生成工作。所以最后我决定使用@IdClass。

经过一番研究,我想出了下一个代码:

@Entity
@IdClass(PartidaId.class)
@Table(name = "partida", schema="trueskill")
public class Partida implements Serializable 

    private static final long serialVersionUID = 659832134987666699L;

    @Id
    @GeneratedValue
    @Column(name ="partida_id")
    private Integer partida_id;

    @Id
    @Column(name = "jugador_id", insertable = false, updatable = false)
    private Integer jugador_id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "jugador_id", referencedColumnName = "id")
    private Jugador jugador;

    @Column(name = "PUNTOS")
    private int puntos;

    ....


public class PartidaId implements Serializable 

    private static final long serialVersionUID = 997366452999076354L;

    private Integer jugador_id; 
    private Integer partida_id;
    ...

它编译正确但是当我尝试持久化一个实体时:

Jugador p1 = new Jugador("Player1");
Partida part1 = new Partida(7, p1);
em.persist(p1);
em.persist(part1);

我收到以下错误:

17:54:31,369 DEBUG [org.hibernate.SQL] - insert into trueskill.partida (jugador_id, PUNTOS, partida_id) values (?, ?, ?)
17:54:31,374 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [1] as [INTEGER] - [1]
17:54:31,374 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [2] as [INTEGER] - [7]
17:54:31,374 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [3] as [INTEGER] - [null]
17:54:31,374 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [4] as [INTEGER] - [4]
17:54:31,390 WARN  [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] - SQL Error: 20000, SQLState: XCL14
17:54:31,390 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] - Die Spaltenposition '4' befindet sich außerhalb des Bereichs. Die Anzahl der Spalten für dieses ResultSet liegt bei '3'.
17:54:31,392 ERROR [org.hibernate.internal.ExceptionMapperStandardImpl] - HHH000346: Error during managed flush [org.hibernate.exception.GenericJDBCException: could not insert: [model.Partida]]

问题是它试图插入一个额外的“空”参数,而应该只有 3 个。有人能告诉我为什么会这样吗?

提前感谢您!

【问题讨论】:

【参考方案1】:

partida 实体中不需要整数 jugador_id。您可能在 jugador 实体中有一个 @Id,它与 partida 类以 @oneToMany 关系映射。

从 Partida 中删除:

@Id
@Column(name = "jugador_id", insertable = false, updatable = false)
private Integer jugador_id;

在 Partida 实体中使用它:

@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "jugador_id", referencedColumnName = "id")
private Jugador jugador;

确保你的 Jugador 类中有类似的东西。

@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "partida", referencedColumnName = "partida_id")
private Partida partida;

正如我在答案中所说,您必须在实体 Jugador 中有此代码:

@Id
@Column(name = "jugador_id", insertable = false, updatable = false)
private Integer jugador_id;

【讨论】:

非常感谢您的回答。我试过你说的:在Partida类中:@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "jugador_id", referencedColumnName = "id") private Jugador jugador;在Jugador类中:@OneToMany(fetch = FetchType.LAZY) @JoinColumn(name = "partida", referencedColumnName = "partida_id") private List<Partida> partidas;但是现在hibernate抱怨因为:There is no primary key attribute to match the ID class attribute jugador_id 不客气。这里的问题是在你的 Jugador 类中不是 @Id 你只需要复制我所说的: @Id @Column(name = "jugador_id", insertable = false, updatable = false) private Integer jugador_id;

以上是关于如何正确映射与@IdClass 的多对一关系?的主要内容,如果未能解决你的问题,请参考以下文章

如何防止 EntityType 在与同一实体(父)的多对一关系中显示当前对象?

Django - 与子类的多对一关系

django--ORM表的多对一关系

JPA命名查询中的多对一关系

将 JSON 中的多对一关系保存到 Core Data

如何在 Elixir 或 SQLAlchemy 中为与其自身的多对一关系创建可自定义的“排序依据”?