Hibernate композитный идентификатор слияния

Я использую 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 объектами отдельно. Первый и второй работают нормально, но когда я пытаюсь слить () третий, postgresql получает нулевое значение вместо идентификатора и возникает исключение нарушения ограничения. Зачем? Могу ли я даже использовать слияние на этой сущности, чтобы добавить новые строки в таблицу?

обновление: слияние что-то вроде этого:

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

где доступность десериализуется из внешнего интерфейса (просто чтобы упомянуть, что коллекции "ключевых" классов в нем отделены).

2 ответа

Решение

Я решил проблему, избегая использования Composite 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;

...
}

Вы уже решили свою проблему, но я оставляю здесь предложение для пользователей, которым необходимо использовать первичные ключи из нескольких столбцов и которые не могут изменить базу данных.

Очевидно, что использование нескольких аннотаций @Id само по себе приводит к несогласованности при попытке слияния: вы присваиваете все поля, а затем во время слияния поля, помеченные @Id, получают присвоенные нулевые значения (и слияние завершается неудачно). Я могу угадать объяснение: hibernate не ожидает, что будет неуправляемый объект с назначенными @Ids; но это проблема только с несколькими первичными ключами столбцов, так что, похоже, это ошибка.

Примечание: вызов сохранится вместо слияния (но в некоторых случаях вы дублируете строки или получаете ошибки ограничения базы данных, поскольку первичный ключ в этом случае проверяется только на уровне базы данных).

Я решил похожую проблему, используя @IdClass. В вашем старом коде вы должны:

  1. Создайте класс (например, AvailabilityId) с полями first и second (точно совпадающими с полями, аннотированными @Id в классе Availability) и переопределив методы equals и hashCode
  2. В AvailabilityId аннотации не требуются, кроме @Override (кстати, если вы используете @Column в полях Availability и AvailabilityId, вы можете получить чудовищные ошибки). Это не должна быть сущность или таблица, это POJO.
  3. Аннотировать доступность класса с помощью @IdClass(AvailabilityId.class)

Это должно быть так. Извините за опоздание на 3 года, но если вы избавились от первичного ключа из нескольких столбцов, вы все равно оказались в лучшем мире.

Я попробовал @EmbeddedId, но он нарушил пару других требований (простое преобразование json->object и запросы, работающие как в SQL, так и в HQL с небольшими изменениями).

Другие вопросы по тегам