【问题标题】:How to eliminate Cascade.ALL in a JPA Relation?如何消除 JPA 关系中的 Cascade.ALL?
【发布时间】:2013-07-22 07:26:21
【问题描述】:

我的实体之间有一个复杂的层次结构。 由于错误(见下文),我在许多地方放置了 CASCADE.ALL 或 CASCADE.PERSIST。从上到下,注释都可以。但自下而上,这不是我想要的。

导致对象被重复保存。

我该如何解决这个问题??

附:为什么我需要 C 和 F 之间的关系:因为这是我获取 F 对象的标准方式。 (目前 %90 的用例)

** Java 代码 -- 创建 A-Tree **

   public A convertToA(final QueryAType aType, final A parent) {
        final A a = new A();

        if (parent != null) {
            a.setVater(parent);
        }

        final List<A> children = new ArrayList<A>();
        for (final QueryAType childPart : aType.getUnterbauteil()) {
            children.add(convertToA(childPart, a));
        }

        final List<B> bList = new ArrayList<B>();
        for (final QueryBType bType : aType.getBType()) {
            bList.add(convertToB(bType, a));
        }
        a.setBList(bList);
        a.setKinder(children);
        return a;
    }

    public B convertToB(final QueryBType bType, final A a) {
        final B b = new B();
        b.setA(a);

        final List<C> cList = new ArrayList<C>();
        for (final QueryCType cType : bType.getCType()) {
            cList.add(convertToC(cType, b));
        }
        b.setCList(cList);
        return b;
    }

    public C convertToC(final QueryCType cType, final B b) {
        final C c = new C();
        c.setB(b);

        final List<D> dList = new ArrayList<D>();
        for (final QueryDType dType : cType.getDType()) {
            dList.add(convertToD(dType, c));
        }
        c.setDList(dList);
        return c;
    }

    public D convertToD(final QueryDType dType, final C c) {
        final D d = new D();
        d.setProbe(c);

        final List<E> eList = new ArrayList<E>();
        for (final QueryEType eType : dType.getEType()) {
            eList.add(convertToE(eType, d, c));
        }

        d.setEList(eList);

        return d;
    }

    public E convertToE(final QueryEType eType, final D d, final C c) {
        final E e = new E();
        e.setD(d);

        final List<F> fList = new ArrayList<F>();
        for (final QueryFType fType : eType.getFType()) {
            fList.add(convertToF(fType, e, c));
        }
        e.setFList(fList);
        c.setFList(fList);
        return e;
    }

    public F convertToF(final QueryFType fType, final E e, final C c) {
        final F f = new F();
        f.setC(c);
        f.setE(e);

        final List<G> gList = new ArrayList<G>();
        for (final QueryGType gType : fType.getGType()) {
            gList.add(convertToG(gType, f));
        }
        f.setGList(gList);

        return f;
    }

    public G convertToG(final QueryGType gType, final F f) {
        final G g = new G();
        g.setMethode(f);
        return g;
    }

没有级联的错误:


org.apache.openjpa.persistence.InvalidStateException: 在通过字段“com.xxx.yyy.data. entity.Fe”在刷新期间。但是,该字段不允许级联持续存在。您不能刷新与非托管对象具有持久关联的非托管对象或图形。建议的操作:a) 将此字段的 cascade 属性设置为 CascadeType.PERSIST 或 CascadeType.ALL(JPA 注释)或“persist”或“all”(JPA orm.xml),b)全局启用 cascade-persist,c)手动在刷新之前保留相关的字段值。 d) 如果引用属于另一个上下文,则通过设置 StoreContext.setAllowReferenceToSiblingContext() 允许对其进行引用。失败对象:com.xxx.yyy.data.entity.E@18e0a217


【问题讨论】:

  • c.fe.f 是对同一个实体的引用还是可能都引用不同的实例?
  • @Thomas 他们是同一个实体。您从 C 和所有 E 实体获得的 F 实体的数量相等。
  • 同一个实体并不意味着它们是同一个实例。检查 C 引用的 F == E 引用的 F。您如何管理 C(持久化或合并)?
  • @Chris。它们是相同的实例
  • C、D 和 E 是如何管理的?您是否在已读入的现有树上调用合并,是否有新的 E 实例等。需要有关对象树的更多详细信息,例如它是否有效?

标签: java jpa cascade openjpa


【解决方案1】:

假设问题是:如果你坚持F;实体 E 被持久化了两次。

在持久化实体 F 之前,setE() 和 setC() 应该在实体 F 的 setter 中完成。

【讨论】:

    【解决方案2】:

    如果不深入研究规范,我不太确定这一点,但我猜会发生这种情况:

    您假设以下情况:如果 F 被持久化,则持久化通过 C 和 D 级联到 E。

    然而,OpenJPA 扫描 F 并看到两个关系:F.cF.e。它将持久化级联到 C,但由于 F.e 没有标记为级联,OpenJPA (尚)不知道 E 也将被持久化(因为它没有完成处理 F)。因此你得到了错误。

    F.eE.d 添加级联应该可以解决问题。

    编辑: 即使您首先持久化 C(直接或通过级联),OpenJPA 可能会尝试在 D 之前处理 F。因此,当处理 F.e 时,OpenJPA 不知道 E也将被持久化(级联 D.e 尚未处理)。

    另一个解决方法可能是在 C 中重新排列关联的顺序。我说 可能,因为我不知道 OpenJPA 处理关联的顺序和级联,但老实说,我不会依赖任何命令。因此,将级联添加到F.e 等似乎是更稳健的选择。

    编辑 2:

    对于重复的持续问题,您可以尝试稍微破坏一下图表。 考虑拥有方:F 拥有与 C 和 E 的关系,E 拥有与 D 的关系,D 拥有与 C 的关系。

    因此,如果您坚持 C,则级联将包括 F,然后应包括 E 和 D。无论如何,D 将保持不变,因此您不需要 C.d 上的级联,这可能会导致重复。我会尝试删除C.dD.e 上的级联。

    【讨论】:

    • 我已经解决了添加注释的问题,但问题是对象被重复保存
    • 我删除了 C.d 和 D.e 上的级联。我又遇到了同样的错误。
    • @Kayser 哪个错误,重复?您是否将级联添加到F.e?您在哪个实体开始持久级联?
    • 我收到错误“没有级联的错误”。我开始由 B 级联
    • @Kayser 到目前为止,我在您的代码中发现的唯一可能的错误可能是 c.setFList(fList);:据我了解您的模型每个 C 可以有多个 E,因此您可以有多个列表Fs。在这种情况下,c.setFList() 似乎用当前 E 引用的 F 替换列表,并且从当前 C 到其其他 F 的所有引用都可能丢失(这可能会影响级联,具体取决于您最终使用注释的方式) .
    猜你喜欢
    • 2018-08-28
    • 2014-03-04
    • 2018-07-09
    • 2011-12-06
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多