【问题标题】:Why does eclipselink/jpa attempt to persist an entity while I don't ask it to?为什么 eclipselink/jpa 在我不要求的情况下尝试持久化实体?
【发布时间】:2010-09-16 02:47:14
【问题描述】:

我试图在一个事务中持久化 3 个实体 (exp,def,meng),然后再持久化另外 2 个 (def', meng'),其中 meng' 与 exp 相关。

但是,当我试图坚持 meng 时,eclipselink/jpa2 被告知:

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

这将抛出一个表达式,因为它已经被插入并且它是一个键。 所以显然坚持实体 meng' 包括更新 exp 本身会以某种方式使 eclipselink 认为我要求坚持一个新的 exp。

这是测试:

@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;
    }

您可以从here 签出 Maven 源代码(进行测试)。

这是预期的行为吗?如果是这样,为什么?还有最重要的,怎么解决?

好像

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

意义是罪魁祸首,虽然我不明白为什么会这样。 documentation 说:

如果实体已被管理,则忽略持久化操作,尽管持久化操作将级联到在关系注释中将级联元素设置为 PERSIST 或 ALL 的相关实体。

【问题讨论】:

    标签: java orm eclipselink jpa-2.0


    【解决方案1】:

    弗兰克是正确的。您没有在表达式中阅读,因此当您在含义上调用 persist 时,当它引用现有表达式时,它们会被分离,这会导致事务失败。调用 merge 将起作用,或者您可以删除 exps 关系上的级联持久性,因为您似乎直接保留了新的表达式,无论如何它不需要。

    【讨论】:

    • 所以这可以更精细:@ManyToMany(cascade={CascadeType.MERGE, CascadeType.REFRESH, CascadeType.REMOVE})。但是,一旦我删除了一个表达式(在删除了数据库中的所有 mengs 后,我在表 'EXPRESSION' 上得到了 DELETE,导致违反了外键约束 'MNNGXPRSSXPSXPRSSN'。
    【解决方案2】:

    你很可能会遇到:

    [...] 如果实体被分离 [...] 事务提交将失败。

    (与您引用的来源相同)

    如果您持久化引用已持久化实体的新实体,则必须使用“合并”而不是“持久化”。 “合并”将保留新实体并更新现有实体。

    还要注意合并操作将返回一个附加的数据图,必须将其用于同一持久性上下文中的进一步操作。

    【讨论】:

    • 因此,如果从含义中删除所有级联注释属性,则坚持应该有效。看起来确实如此,但不知何故,该实体潜伏在周围。确实,当我要删除所有不是的含义时(当我通过持有实体的级联操作删除时)。如果我确实尝试显式删除它,我会从绑定删除包含 exp 和 meng 实体的关系的表中得到一个异常。为什么?
    猜你喜欢
    • 2011-11-01
    • 2023-03-29
    • 2013-05-15
    • 2014-02-13
    • 2016-03-28
    • 2023-03-09
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多