Слияние составных идентификаторов 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
}

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

update: слияние выглядит примерно так:

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

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


person Community    schedule 26.05.2014    source источник
comment
Привет! Опубликуйте фрагмент кода, где вы приводите пример того, как вы объединяете этот объект. Возможно, это может быть только проблема операции каскадного слияния.   -  person gipinani    schedule 26.05.2014
comment
Готово, но ничего особенного. Я использую такие операции возврата-слияния для добавления/обновления строк во многих местах проекта, думая, что это сработает и для этого объекта.   -  person    schedule 27.05.2014


Ответы (2)


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

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

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

Я решил аналогичную проблему, используя @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 с небольшими настройками).

person Matteo Steccolini    schedule 18.10.2017

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

...
}
person Community    schedule 28.05.2014