【问题标题】:@ManyToOne(fetch=FetchType.LAZY) lazy loading not working@ManyToOne(fetch=FetchType.LAZY) 延迟加载不起作用
【发布时间】:2014-09-02 14:53:50
【问题描述】:

我正在使用 JPA 2.1 (EclipseLink 2.5.1) 和 JBoss 7.1。

我已经定义了非常简单的 JPA 实体:

@Entity
@Table(name="APLICACIONES_TB")
public class Aplicacion implements Serializable {

  @Id
  @Column(name="COD_APLICACION_V")
  private long codAplicacionV;

  @Column(name="APLICACION_V")
  private String aplicacionV;

  @OneToMany(mappedBy="aplicacion")
  private Collection<Prestacion> prestaciones;

  ... getters and setters
}

@Entity
@Table(name="PRESTACIONES_TB")
public class Prestacion implements Serializable {

  @Id
  @Column(name="COD_PRESTACIONES_V")
  private String codPrestacionesV;

  @Column(name="DESCRIPCION_V")
  private String descripcionV;

  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name = "COD_APLICACION_V")    
  private Aplicacion aplicacion;

  ... getters and setters ...
}

我开发了一个过时的 EJB,它执行查询以获取一些“应用程序”实体。

@Stateless
@LocalBean
public class DocuEJB implements DocuEJBLocal
{
  @PersistenceContext(name="DocuEjb", type=PersistenceContextType.TRANSACTION)
  private EntityManager em;

  public Prestacion getResult(String name)
  {
    return em.createNamedQuery("ExampleQueryName", Prestacion.class).getSingleResult();
  }
}

因为我使用的是 JSF 2.1,所以 EJB 被注入到托管 bean 中:

@ManagedBean(name = "ManagedBean")
@RequestScoped
public class ManagedBean
{   
  @EJB DocuEJB docuEjb;

  public String doSomething()
  {
     Prestacion entity = docuEjb.getResult("egesr");

     if (entity != null)
     {
        // It should return null because 'entity' should be detached
        Aplicacion app = entity.getAplicacion();

        // but 'app' entity is not null, ¿why not?
        System.out.println (app.getCodAplicacionV());
     }
  }
}

即使为“Prestacion”实体上的“aplicacion”字段定义了延迟加载,延迟加载也不起作用。之前发布的代码应该在下一行返回 NullPointerException:

System.out.println (app.getCodAplicacionV());

因为 'app' 实体已分离且已配置延迟加载。

为什么延迟加载不工作?

谢谢

【问题讨论】:

  • 尝试在 doSomething() 上添加@Transactional
  • 如果在分离的对象中调用 getAplicacion(),它应该引发臭名昭著的 LazyInitializationException。不是...所以应用程序仍然附加。
  • @Xstian - 我已经尝试过你的建议(事务持久性上下文),但我得到了相同的结果。
  • @Ivan.aguirre - 但它不能附加,因为我在 ejb 中使用事务持久性上下文,所以当 ejb 方法完成时,持久性上下文是清晰的,所有实体都被分离。我在所有 JPA 书籍中都读过这一点
  • 我在互联网上读到,即使实体已分离,惰性链接也可以与 EclipseLink 提供程序一起使用。在这种情况下,EclipseLink 将简单地从连接池中获取一个只读连接,执行加载,然后将连接放回池中。我在下一个链接中读到了这个:softaria.com/2011/07/26/eclipselink-versus-hibernate。但我想在 EclipseLink 文档中找到这个解释。

标签: jpa eclipselink lazy-loading


【解决方案1】:

尝试在doSomething()上添加@Transactional,我认为你的事务管理器配置不好。

可以查看herespring 官方文档。无论如何,您可以添加您的弹簧配置,以便我们更好地帮助您。 :)

【讨论】:

  • 当你说@Transactional,你的意思是@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)注解吗? doSomething 是一种 EJB 方法
  • 我的想法是,当您尝试获取关系时,事务已关闭。我建议你像 SpringTransaction 这样的行为。
【解决方案2】:

我认为你遇到的行为不正常或者你的问题应该说清楚:

  • EJB 默认是事务性的
  • 您的 JSF 使用 @EJB 注入 EJB,我猜 JBoss 可以创建 java 引用而不是代理
  • 由于事务未完成,实体正在被管理,它将在doSomething 结束时完成。

然后您的实体被加载到EntityManager,并且延迟加载工作,因为它有一个上下文。

您将调用 em.evict(entity) 得到您得到的结果,这可能会失败,因为该实体将不再被管理。

【讨论】:

  • 我同意你的看法。但是,如果您查看我发布的代码,那么一旦“doSomething”方法结束,惰性引用就会被解决。由于这个原因,它不应该解决惰性引用。
  • 例如,它在哪里不应该被延迟加载? (因为您的示例指向doSomething,而不是您使用它的真实位置)。 .
  • 对不起,你是对的,我解释得不好。 'getResult' 方法是一个 EJB 方法,因为为 EJB 定义的持久性上下文类型是事务性的,所以应该分离 'getResult' 方法返回的实体。另一方面,“doSomething”方法是托管 bean 方法,我认为 JEE 容器不管理托管 bean 方法的事务。
  • 它正在被延迟加载,它不应该在下一行:Aplicacion app = entity.getAplicacion();
猜你喜欢
  • 1970-01-01
  • 2011-08-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-18
相关资源
最近更新 更多