简体   繁体   English

Hibernate复合ID合并

[英]Hibernate composite id merge

I'm using Hibernate with JPA and have a relation like this: 我正在将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
}

I want to manage these 3 entities separately. 我想分别管理这三个实体。 First and Second work fine, but when I try to merge() the third one postgresql gets a null value instead of the id's and constraint violation exception is thrown. 第一和第二工作正常,但是当我尝试merge()时,第三个postgresql获取一个空值而不是id,并且抛出了违反约束的异常。 Why? 为什么? Can I even use merge on this entity to add new rows to the table? 我什至可以在此实体上使用merge将新行添加到表中?

update: The merge is something like this: 更新:合并是这样的:

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

where the availability is deserialized from front-end (just to mention, the collections of "key" classes are detached in it). 可用性从前端反序列化(仅提及,“键”类的集合在其中分离)。

You already solved your issue, but I leave here a suggestion for users that need to use multiple-columns primary keys and can't change the database. 您已经解决了您的问题,但是对于需要使用多列主键且无法更改数据库的用户,我这里有一个建议。

Apparently, using multiple @Id annotations by themselves produces an inconsistency when trying to merge: you assign all fields, and then during the merge the fields annotated with @Id get assigned null values (and the merge fails). 显然,尝试合并时单独使用多个@Id注释会产生不一致:分配所有字段,然后在合并期间,用@Id注释的字段将分配为空值 (合并失败)。 I can guess an explanation: hibernate doesn't expect there to be a non-managed object with assigned @Ids; 我可以猜出一个解释:休眠不希望有一个分配了@Ids的非托管对象; but this is an issue only with multiple column primary keys, so it seems to be a bug. 但这仅是多个列主键的问题,因此似乎是一个错误。

Note: calling persist instead of merge works (but in some cases you would duplicate rows or get database constraint errors, because the primary key in this case is checked only at database level). 注意:调用persist而不是merge可以工作(但是在某些情况下,您将复制行或获取数据库约束错误,因为在这种情况下,仅在数据库级别检查主键)。

I solved a similar issue using @IdClass. 我使用@IdClass解决了类似的问题。 In your old code you would have to: 在旧代码中,您将必须:

  1. Create a class (for example AvailabilityId ) with fields first and second (matching exactly the fields annotated with @Id in class Availability), and overriding equals and hashCode methods 创建一个具有第一个字段和第二个字段的类(例如, AvailabilityId )(与在Availability类中用@Id注释的字段完全匹配),并覆盖equalshashCode方法
  2. No annotations are required in AvailabilityId other than @Override (by the way, if you use @Column on both Availability and AvailabilityId fields you can get monstruous errors). 除了@Override以外,在AvailabilityId中不需要任何注释(顺便说一句,如果同时在Availability和AvailabilityId字段上使用@Column,则可能会出现巨大错误)。 This has not to be an entity or a table, it is a POJO. 这不必是实体或表,它可以是POJO。
  3. Annotate class Availability with @IdClass(AvailabilityId.class) 使用@IdClass(AvailabilityId.class)注释类的可用性

That should be it. 应该是这样。 Sorry for being 3 years late, but if you got rid of your multiple column primary key you are in a better world now anyway. 抱歉,我们迟到了3年,但是如果您摆脱了多列主键,现在无论如何您都会处于一个更好的世界。

I tried @EmbeddedId but it broke a couple of other requirements (easy json->object conversion and queries working both in SQL and HQL with minor adjustments). 我尝试了@EmbeddedId,但它打破了其他一些要求(轻松进行json-> object转换以及在SQL和HQL中都可以进行细微调整的查询)。

I solved the problem by avoiding the use of Composite ID. 我通过避免使用Composite ID解决了该问题。 After rethinking the problem I found out that this case I actually can use an unique constraint. 重新思考问题后,我发现这种情况实际上可以使用唯一约束。

@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;

...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM