Почему JPA делает двойную вставку при слиянии () - PullRequest
0 голосов
/ 18 мая 2011

В EclipseLink я сталкиваюсь с проблемой, когда элемент вставляется дважды, что приводит к нарушению первичного ключа.Сценарий таков: у меня есть три объекта: Элемент, Ограничение и Ограничение. Элемент.Объект RestrictionElement действует как отношение «многие ко многим» между двумя другими.Когда я создаю новый RestrictionElement и объединяю Элемент, RestrictionElement вставляется дважды.Код:

// element is an Element, restriction is a Restriction. Both are already in present in the database.
RestrictionElement newRestrictionElement = new RestrictionElement(restriction, element);
Transaction transaction = new Transaction();
em.merge(element); //em is the EntityManager
transaction.commit();

Однако, если я удаляю строку restriction.getReferencedRestrictionElements().add(this);, RestrictionElement вставляется один раз.Кто-нибудь может объяснить, почему это происходит?Или укажите документ, который объясняет, как определить, что делает команда merge ()?

Соответствующий код JPA: (Я приведу лишь небольшую часть. Других больших проблем с кодом нет..)

public class RestrictionElement {

    @JoinColumns({@JoinColumn(name = "ELEMENT_ID", referencedColumnName = "ID"),@JoinColumn(name = "ELEMENT_DESCRIPTOR", referencedColumnName = "DESCRIPTOR")})
    private Element element;

    @JoinColumns({@JoinColumn(name = "RESTRICTION_ID", referencedColumnName = "ID"),@JoinColumn(name = "RESTRICTION_DESCRIPTOR", referencedColumnName = "DESCRIPTOR")})
    private Restriction restriction;

    public RestrictionElement(Restriction restriction, Element element) {
        this.restriction = restriction;
        this.element = element;
        restriction.getReferencedRestrictionElements().add(this);
        element.getReferingRestrictionElements().add(this);
    }
}

public class Element {
    @OneToMany(mappedBy = "element")
    private List<RestrictionElement> referingRestrictionElements = new ArrayList<RestrictionElement>();
}

public class Restriction extends Element {
    @OneToMany(mappedBy = "restriction", cascade = { ALL, PERSIST, MERGE, REMOVE, REFRESH })
    private List<RestrictionElement> referencedRestrictionElements = new ArrayList<RestrictionElement>();
}

Ответы [ 3 ]

2 голосов
/ 19 мая 2011

Как вы сохраняете RestrictionElement?Я предполагаю, что когда вы сохраняете его, вы получаете одну копию, а затем вторую при объединении элемента со ссылкой на него.

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

1 голос
/ 22 августа 2012

У меня возникла похожая проблема, когда я запускаю свою программу, но эта проблема отсутствует при пошаговой отладке.

Я решил проблему, изменив Список на Установить в отношении OneToMany.

1 голос
/ 20 мая 2011

Не забывайте, что после извлечения экземпляра класса с использованием JPA экземпляр становится управляемым, любые изменения в нем будут автоматически объединены в базу данных.

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

  • запрос (поиск по идентификатору)
  • update (setName = "xx")
  • запрос другого класса, который имеет прямую связьк этому (снова найти по идентификатору)

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

Я предлагаю вам выполнить каждый отдельный запрос (например, findById) или каждый ваш экземпляр до того, как вы начнете изменять его (т. Е. Установить,и т.д.).

Надеюсь, это поможет.

...