Будьте в спящем режиме инициировав ограничительные нарушения с помощью orphanRemoval

Я испытываю затруднения из-за JPA/Hibernate (3.5.3) установка, где у меня есть объект, класс "Учетной записи", который имеет список дочерних объектов, экземпляров "Контакта". Я пытаюсь смочь добавить/удалить экземпляры Контакта в свойство Списка Учетной записи.

Добавление нового экземпляра в набор и вызов saveOrUpdate (учетная запись) сохраняют все прекрасное. Если я затем принимаю решение удалить контакт из списка и снова назвать saveOrUpdate, SQL В спящем режиме, кажется, производит, включает установку в NULL account_id столбца, который нарушает ограничение базы данных.

Что я делаю неправильно?

Код ниже является ясно упрощенным кратким обзором, но я думаю, что он покрывает проблему, поскольку я вижу те же результаты в другом коде, который действительно является об этом простом.

SQL:

CREATE TABLE account ( INT account_id );
CREATE TABLE contact ( INT contact_id, INT account_id REFERENCES account (account_id) );

Java:

@Entity
class Account {
  @Id
  @Column
  public Long id;

  @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
  @JoinColumn(name = "account_id")
  public List contacts;
}

@Entity
class Contact {
  @Id
  @Column
  public Long id;

  @ManyToOne(optional = false)
  @JoinColumn(name = "account_id", nullable = false)
  public Account account;
}

Account account = new Account();
Contact contact = new Contact();

account.contacts.add(contact);
saveOrUpdate(account);

// some time later, like another servlet request....

account.contacts.remove(contact);
saveOrUpdate(account);

Результат:

UPDATE contact SET account_id = null WHERE contact_id = ?

Редактирование № 1:

Могло бы случиться так, что это - на самом деле ошибка http://opensource.atlassian.com/projects/hibernate/browse/HHH-5091

Редактирование № 2:

У меня есть решение, которое, кажется, работает, но включает использование Быть в спящем режиме API

class Account {
    @SuppressWarnings("deprecation")
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "account")
    @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    @JoinColumn(name = "account_id", nullable = false)
    private Set contacts = new HashSet();
}

class Contact {
    @ManyToOne(optional = false)
    @JoinColumn(name = "account_id", nullable = false)
    private Account account;
}

С тех пор В спящем режиме CascadeType. DELETE_ORPHAN удерживается от использования, я должен предположить, что он был заменен версией JPA2, но реализация испытывает недостаток в чем-то.

15
задан Pascal Thivent 26 June 2010 в 00:10
поделиться

1 ответ

Некоторые примечания:

  • Поскольку у вас двунаправленная ассоциация, вам необходимо добавить атрибут mappedBy для объявления стороны-владельца ассоциации.
  • Также не забывайте, что вам нужно управлять обеими сторонами ссылки при работе с двунаправленными ассоциациями, и я предлагаю использовать для этого защитные методы (показаны ниже).
  • И вы должны реализовать равно и hashCode в контакте .

Итак, в Аккаунте измените отображение следующим образом:

@Entity
public class Account {
    @Id @GeneratedValue
    public Long id;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "account", orphanRemoval = true)
    public List<Contact> contacts = new ArrayList<Contact>();

    public void addToContacts(Contact contact) {
        this.contacts.add(contact);
        contact.setAccount(this);
    }

    public void removeFromContacts(Contact contact) {
        this.contacts.remove(contact);
        contact.setAccount(null);
    }

    // getters, setters
}

В Контакт важная часть состоит в том, что в поле @ManyToOne должно быть указано необязательный флаг установлен на false :

@Entity
public class Contact {
    @Id @GeneratedValue
    public Long id;

    @ManyToOne(optional = false)
    public Account account;

    // getters, setters, equals, hashCode

}

С этими изменениями работает следующее:

Account account = new Account();
Contact contact = new Contact();

account.addToContact(contact);
em.persist(account);
em.flush();

assertNotNull(account.getId());
assertNotNull(account.getContacts().get(0).getId());
assertEquals(1, account.getContacts().size());

account.removeFromContact(contact);
em.merge(account);
em.flush();
assertEquals(0, account.getContacts().size());

И потерянный Контакт удаляется, как и ожидалось. Протестировано с Hibernate 3.5.3-Final.

19
ответ дан 1 December 2019 в 03:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: