【问题标题】:Why CascadeType.DETACH is not working in OneToMany relationships of FetchType.LAZY in Eclipselink?为什么 CascadeType.DETACH 在 Eclipselink 中的 FetchType.LAZY 的 OneToMany 关系中不起作用?
【发布时间】:2018-04-22 06:13:19
【问题描述】:

在带有JPA 的标准JEE 应用程序中,我有一个主实体A,其中包含B 的一对多集合。A 实体具有以下形式:

@Table(name = "TABLE_A")
@Entity
public class A implements Serializable {

    @Id
    @SequenceGenerator(name = "A_ID_GENERATOR", sequenceName = "SEQ_A", allocationSize = 1, initialValue = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "A_ID_GENERATOR")
    @Column(unique = true, nullable = false, precision = 16)
    private Long id;

    @OneToMany(cascade = CascadeType.ALL , fetch = FetchType.LAZY  , mappedBy = "a")
     private List<B> bCollection;
     public List<B> getB() {
        return this.bCollection;
     }

     public void setB(List<B> bCollection) {
        this.bCollection = bCollection;
     }

     public Long getId() {
         return id;
     }

     public void setId(Long id) {
         this.id = id;
     }

}

实体 B 具有以下形式:

@Table(name = "TABLE_B")
@Entity
public class B implements Serializable {

    @Id
    @SequenceGenerator(name = "B_ID_GENERATOR", sequenceName = "SEQ_B", allocationSize = 1, initialValue = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "B_ID_GENERATOR")
    @Column(unique = true, nullable = false, precision = 16)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "A_FK")
    private A a;

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public A getA() {
        return this.a;
    }

    public void setA(A a) {
        this.a = a;
    }

}

@TransactionAttribute(TransactionAttributeType.REQUIRED) 的 EJB 方法中,我从 DB 中检索 A 并调用 getB() 以获取当前 A 下 B 的数据。然后我手动分离当前 A:

em.detach(a);

在 EJB 方法返回之前,如果我使用 em.contains(b) 测试当前 A 下的 B 实例,即使我使用 CascadeType.ALL,它们仍然受到管理。

EJB 中的事务方法如下所示:

@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void doSomething(String aBusinessKey) {

    A a = fetchAByItsBusinessKey(aBusinessKey);
    List<B> bs = a.getB();

    em.detach(a);

    //Test if Bs are managed
    boolean isManaged = em.contains(bs.get(0));

}

谁能解释为什么CascadeType.DETACHFetchType.LAZY 屏蔽?当我将 Fetch Type 更改为 EAGER 时,分离会传播到 B 的详细信息集合。

作为引擎,我使用Eclipse Link

--EDIT 问题是 CascadeType.DETACH 没有在详细集合中传播。所有实体都在分离之前进行管理和获取。

【问题讨论】:

  • 好吧,我可能错了:你的意思是这部分并调用getB()的意思是所有实体在分离之前都被获取和管理
  • 是的,在同一个事务中,我获取一个主实体 A,我调用 getB() 来获取它的 B 类型的详细实体,然后我调用 em.detach(a),我希望实体管理器由于 CascadeType.ALL 而分离 B 实体
  • 你能把你正在使用的B也放进去吗?有没有,如果,那么A 有什么样的注释?我想测试一下。
  • 检查你的第一个代码sn-p:它有注释@OneToOne。然后它有private B b;,但也有List&lt;B&gt; getB(),它返回b?你说 A 包含 B 的一对多集合?因此,您需要在代码中编辑一些内容以使其更易于理解。就像把这些实体像你一样测试它们。
  • @pirho 我编辑了代码以提供 A 和 B 实体并更正拼写错误。

标签: jpa jakarta-ee eclipselink jpa-2.0


【解决方案1】:

Detach 仅对获取的属性和关系进行级联,并且您在分离 A 后获取 B 列表。getB 仅返回提供者的集合实现 - 实际集合的代理,并且不获取结果。只有访问这个集合,比如调用它的 size,才会触发 fetch。

在其他提供程序上,这会导致异常,但只要上下文仍然可用,EclipseLink 就允许获取惰性关系。如果实体未序列化并且 EMF 仍处于打开状态,为了保持对象身份,EclipseLink 将使用从中读取实体的 EntityManager 来获取您的集合,从而在该 EntityManager 中管理结果。

【讨论】:

  • 没错。我用@OneToOne 测试了OPs 代码,只得到了一个B,一切正常,因为它获取了实体。但是对于列表来说就是这样。如果这合适,我不知道(如果不合适,我会删除)但也许你对我的松散相关问题有话要说here
  • @Chris 我编辑代码以提供两个实体并更正拼写错误。不,我在事务中和分离之前执行 Bs 的获取,因此 Bs 可以按我的预期正常获取。问题是,如果我在分离当前 A 后检查 B,即使我使用 CascadeType.ALL,它们仍然受到管理
  • @IliasStavrakis 也将其放入您的问题中。或者最好是一段代码循环所有Bs,之后级联分离仍然失败。那是因为你的调试会话很难被其他人重复。
  • 如果你在List&lt;B&gt; bs = a.getB(); 之后-在刷新之前-bs.get(0) 是一样的吗?这是克里斯回答的重点。因此,不仅在您的调试器中,而且在代码中也显示您已填充列表。
  • getBs 不获取 Bs。您的调试器应该显示您拥有的是一个 EclipseLink 代理类的实例,它包装了集合,允许仅在真正需要实例时才延迟获取它。在您尝试访问集合中的 B 之前,不会获取它,此时代理将从数据库(或共享缓存)填充引用列表。
猜你喜欢
  • 1970-01-01
  • 2013-10-10
  • 1970-01-01
  • 2012-01-08
  • 1970-01-01
  • 1970-01-01
  • 2018-09-08
  • 1970-01-01
  • 2013-11-09
相关资源
最近更新 更多