【问题标题】:EclipseLink merge unexpected cascadeEclipseLink 合并意外级联
【发布时间】:2012-08-11 01:10:59
【问题描述】:

我有两个实体类用户和设备。

用户实体:

public class User {
    private Long userId;

    @OneToMany( mappedBy = "userId", fetch = FetchType.LAZY)
    private Collection<Device> deviceCollection;

和设备实体:

public class Device implements Serializable {
    @JoinColumn(name = "user_id", referencedColumnName = "user_id")
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    private User userId;

当我在删除父用户后将以前分离的设备实体合并到实体管理器中时,(以前删除的)用户和设备都会重新插入到数据库中。用户或设备实体上没有级联注释;因此,我不希望重新插入用户实体,但确实如此;

如何防止合并操作级联到用户实体?

提前致谢。

【问题讨论】:

  • 我认为这是 EclipseLink 中的一个错误。

标签: jpa eclipselink


【解决方案1】:

您在分离状态下所做的任何更改,会话管理器都无法知道它,因此更改始终是需要合并的新对象(如果您正在调用合并)

所以当你调用合并时,它会从数据库中加载它,这样你的对象就会有 Prev+ 新的变化。这就是为什么发生上述行为的原因。

您可以做的是首先在会话中加载实体应用更改,然后调用合并。

你可以做的是类似下面的事情,我在我的一个项目中使用 Eclipse Link 使用了类似的关系

Query query = entityManager
            .createNamedQuery("User.FindByUserId");
    User fromDatabase = null;
    try {
        query.setParameter("userId", device.getUser().getUserId());
        fromDatabase = (User) query.getSingleResult();

    } catch (NoResultException noResultException) {
        // There is no need to do anything here.
    }
    if (fromDatabase == null) {
        User user= entityManager.merge(device.getUser());
         device.setUser(user);
    } else {
        device.setUser(user);
    }
    entityManager.persist(device);

【讨论】:

  • 但我希望它不会合并用户实体,因为没有指定级联选项。这是否意味着合并操作总是级联的,无法关闭?
  • 同样,它是特定于提供商的,但对我有用的是@OneToMany(cascade={}) 这就像指定级联 NONE。请尝试让我知道。
  • 我尝试将 cascade = {} 放在用户实体 (OneToMany) 和设备实体 (ManyToOne) 上;效果是一样的。用户实体仍被重新插入。
【解决方案2】:

尝试将 insertable=false, updatable=false 添加到您的 JoinColumn,例如

@JoinColumn(name = "user_id", referencedColumnName = "user_id", insertable=false, updatable=false)

【讨论】:

  • 这也无济于事。用户行仍然插入。
【解决方案3】:

我遇到了同样的问题 我发现了一个关于这个的错误:EntityManager.merge() cascading by default 但我真的不明白为什么这种行为永远无法解决。这是我不使用 EclipseLink 的原因之一(但这不是重点)

编辑:

克里斯,以“我不是专家”开头的评论放在头脑中的论点是不正确的,我认为。我的理解是,它只是具有没有 cascade=MERGE 或 cascade=ALL 的关系的实体,您可以导航,仅此而已。

否则为什么要使用 Merge 注释?这没有意义。

【讨论】:

  • 作为错误状态的最后一篇文章,规范指出,在未标记级联合并的关系上引用分离实体仍将返回托管实例。它没有说明该托管实例的含义或方式。如果这是阻止您尝试 Eclispelink 的唯一原因,我怀疑您是否真的给了它机会。
  • 规范声明在 X 上合并返回 X'。如果 X 引用 Y,则 X' 引用托管 Y'。如果 Y' 是托管的,它就是与数据库同步的东西。如果 Y' 是非托管对象,则规范将其完全打开,而大多数用户理解并希望托管 Y' 实例(如果存在)。您使用级联合并选项将您的更改放入现有的 Y' 实例 - 如果 Y' 已经存在,合并 X 不会将 Y 合并到 Y' 中。该规范没有您可以浏览的托管实体的概念。它是受管理的,或者不是。
【解决方案4】:

您应该使用版本号来防止实体被错误地复活。这将强制出现一个异常,因为规范对于在未标记为 cascade all 或 merge 的关系上进行合并时应该发生什么有点不清楚。规范指出托管实体将同步到数据库,而处理合并的部分意味着即使是由关系引用的实体,没有级联合并/所有选项也将在之后进行管理。这种行为可能不是预期的,但在澄清之前不应依赖。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-27
    • 2016-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-23
    • 1970-01-01
    相关资源
    最近更新 更多