Почему eclipselink / jpa пытается сохранить сущность, пока я об этом не прошу?

Я пытаюсь сохранить 3 объекта (exp, def, meng) в транзакции, а затем сохранить еще 2 (def ', meng'), где meng 'связано с exp.

Однако, когда я пытаюсь сохранить meng, eclipselink / jpa2 получает указание:

Call: INSERT INTO EXPRESSION (EXPRESSION, GENDER) VALUES (?, ?)
    bind => [exp, null]

который выдаст выражение, поскольку оно уже было вставлено и является ключом. Таким образом, очевидно, что сохранение сущности meng ', которая включает в себя обновление самого опыта, каким-то образом заставит eclipselink думать, что я просил сохранить новый опыт.

Вот тест:

@Test
public void testInsertWords() throws MultipleMengsException, Exception{
    final List<String[]> mengsWithSharedExp = new LinkedList<String[]>();
    mengsWithSharedExp.add(mengsList.get(3));
    mengsWithSharedExp.add(mengsList.get(4));

    insertWords(mengsWithSharedExp, null, mengsDB);
}

Вот проблемный код:

public void insertWords(EnumMap<Input, MemoEntity> input) throws MultipleMengsException {
    Expression def = (Expression) input.get(Input.definition);
    Expression exp = (Expression) input.get(Input.expression);
    beginTransaction();
    persistIfNew(def);
    persistIfNew(exp);
    persistNewMeng(null, exp, def);
    commitTransaction();
}

private void persistNewMeng(final MUser usr, Expression exp, final Expression def) throws RuntimeException {
    final Meaning meng = new Meaning(usr, exp, def);
    if (!persistIfNew(meng)) {
        throw new RuntimeException("Meng ." + meng.toString() + " was expected to be new.");
    }
    if (usr != null) {
        usr.addMeng(meng);
    }
}

public <Entity> boolean persistIfNew(final Entity entity) {
        final Object key = emf.getPersistenceUnitUtil().getIdentifier(entity);
        if (em.find(entity.getClass(), emf.getPersistenceUnitUtil().getIdentifier(entity)) != null) {
            return false;
        }
        em.persist(entity);
        return true;
    }

Вы можете проверить исходный код Maven (для тестирования) здесь.

Это ожидаемое поведение? Если да, то почему? И самое главное как решить?

Это выглядит так, как будто

@ManyToMany(cascade=CascadeType.ALL)
private Set<Expression> exps;

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

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


person simpatico    schedule 16.09.2010    source источник


Ответы (2)


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

person Chris    schedule 16.09.2010
comment
так что его можно было бы улучшить: @ManyToMany (cascade = {CascadeType.MERGE, CascadeType.REFRESH, CascadeType.REMOVE}). Однако, как только я удаляю выражение (после удаления всех значений в базе данных, я получаю DELETE в таблице EXPRESSION, это вызвало нарушение ограничения внешнего ключа MNNGXPRSSXPSXPRSSN. - person simpatico; 16.09.2010

Скорее всего, вы столкнетесь с:

[...] Если объект отсоединен [...], транзакция завершится неудачно.

(тот же источник, который вы цитируете)

Если вы сохраняете новую сущность, которая ссылается на уже постоянную сущность, вы должны использовать «слияние» вместо «сохранить». «merge» сохранит новые сущности и обновит существующие.

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

person Frank    schedule 16.09.2010
comment
поэтому, если удалить все атрибуты каскадной аннотации из значения, должно работать. Кажется, это так, но каким-то образом сущность продолжает скрываться. Действительно, когда я прихожу к удалению всех значений, которых нет (когда я удаляю через каскадную операцию холдинговой сущности). Если я все же попытаюсь удалить его явно, я получу исключение из привязки к удалению таблицы, которая содержит отношения между сущностями exp и meng. Почему? - person simpatico; 17.09.2010