Hibernate复合id合并

时间:2014-05-26 14:21:03

标签: hibernate jpa merge composite-id

我正在使用Hibernate和JPA,并且有这样的关系:

@Entity
@Table(name = "first")
public class First {
...
@OneToMany(mappedBy = "first")
private List<Availability> availabilities;
...
}


@Entity
@Table(name = "second")
public class Second {
...
@OneToMany(mappedBy = "second")
private List<Availability> availabilities;
...
}

@Entity
@Table(name="availability")
public class Availability implements Serializable {
@Id
@ManyToOne
@JoinColumn(name = "first_id")
private First first;

@Id
@ManyToOne
@JoinColumn(name = "second_id")
private Second second;

@Column(name = "availability")
private Integer availability;

...
hashcode and equals
}

我想分别管理这3个实体。第一个和第二个工作正常,但是当我尝试merge()时,第三个postgresql获取一个空值而不是id和约束违规异常被抛出。为什么?我是否可以在此实体上使用合并向表中添加新行?

更新: 合并是这样的:

public Availability setAvailability(Availability a) {
return em.merge(a);
}

从前端对可用性进行反序列化(仅提及,“密钥”类的集合在其中分离)。

2 个答案:

答案 0 :(得分:2)

您已经解决了问题,但我在此留下了一个建议,指出需要使用多列主键并且无法更改数据库的用户。

显然,在尝试合并时使用多个@Id注释会产生不一致:您指定所有字段,然后在合并期间注释@Id的字段获得指定空值(以及合并失败)。我可以猜到一个解释:hibernate并不期望有一个带有@Ids的非托管对象;但这只是一个问题,只有多列主键,所以它似乎是一个错误。

注意:调用 persist 而不是合并工作(但在某些情况下,您会复制行或获取数据库约束错误,因为在这种情况下仅在数据库级别检查主键)。

我使用@IdClass解决了类似的问题。在您的旧代码中,您必须:

  1. 创建一个类(例如 AvailabilityId ),其中字段第一个第二个(完全匹配类Availability中使用@Id注释的字段) ,并覆盖等于 hashCode 方法
  2. 除了@Override之外,AvailabilityId中不需要注释(顺便说一句,如果在Availability和AvailabilityId字段上使用@Column,则可能会出现明显的错误)。这不是一个实体或一个表,它是一个POJO。
  3. 使用@IdClass(AvailabilityId.class)
  4. 注释类可用性

    那应该是它。抱歉迟到了3年,但如果你摆脱了多列主键,那么无论如何你现在处于一个更美好的世界。

    我尝试了@EmbeddedId,但它破坏了其他一些要求(简单的json-&gt;对象转换和查询在SQL和HQL中都可以进行微调)。

答案 1 :(得分:0)

我通过避免使用复合ID解决了这个问题。在重新思考问题之后,我发现这个案例我实际上可以使用一个独特的约束。

@Entity
@Table(name = "availabilities", uniqueConstraints = { @UniqueConstraint(columnNames = {
    "first_id", "second_id" }) })
@SequenceGenerator(initialValue = 1, name = "availabilities_sequence", sequenceName =     "availabilities_sequence")
public class Availability implements IAvailability, Serializable {

private static final long serialVersionUID = -2977047920673617888L;

@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "availabilities_sequence")
@Column(name = "id")
private Integer id;

@ManyToOne
@JoinColumn(name = "first_id", nullable=false)
private First first;

@ManyToOne
@JoinColumn(name = "second_id", nullable=false)
private Second second;

@Column(name = "availability", nullable=false)
private Integer availability;

...
}