【问题标题】:LEFT JOIN FETCH not working - Spring data JPALEFT JOIN FETCH 不起作用 - Spring 数据 JPA
【发布时间】:2021-09-11 21:46:40
【问题描述】:

我在使用 LEFT JOIN FETCH 时遇到问题。请参考我下面的实体和存储库。

考虑一个场景,选修课程在任何时候都不会从表格中删除。但是可以删除学生信息。 数据库中的两个表之间没有主键和外键关系。只是我们有共同的列“STUDENT_ID”。

@NamedEntityGraphs({
@NamedEntityGraph(
        name = "Student.optionalCourse",
        attributeNodes = @NamedAttributeNode("optionalCourse")
    )
})
@Table("STUDENT")
class Student {

    @Id
    @column_name(STUDENT_ID)
    private integer studentId;

    @column_name(STUDENT_AGE)
    private int studentAge;

    @OneToMany(fetch = FetchType.LAZY, mappedBy="student")
      private List<OptionalCourse> optionalCourse;

}


@NamedEntityGraphs({
@NamedEntityGraph(
        name = "OptionalCourse.student",
        attributeNodes = @NamedAttributeNode("student")
    )
})
@Table("OPTIONAL_COURSES")
class OptionalCourse {

    @Id
    @column_name(ID)
    private Integer id;

    @column_name(STUDENT_ID)
    private Integer studentId;

    @column_name(SUBJECT_NAME)
    private String subjectName;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "STUDENT_ID" , referencedColumnName="STUDENT_ID", insertable = false, updatable = false )
    private Student student;

}


@Repository
@Transactional(rollbackFor = Exception.class)
public interface OptionalCourseRepository extends JpaRepository<OptionalCourse,Integer> {

  @Query(value = "SELECT oc FROM OptionalCourse oc LEFT JOIN FETCH oc.student where oc.studentId > :studentId",
      countQuery = "SELECT count(oc.id) FROM OptionalCourse oc where oc.studentId > :studentId")
  public Page<OptionalCourse> findOptionalSubjectPagesByStudentId(@Param("studentId") Integer studentId, Pageable pageable);

}

没有事务的服务方法:

public List<CustomBeanClass> retrieveRpdLogRequestsList(Integer studentId, Integer pageIndex, Integer pageResultsSize) {

    Pageable pageWithIndexAndSize = Pageable.unpaged();
    
    if(Objects.nonNull(pageIndex) && Objects.nonNull(pageResultsSize) && pageIndex >= 0 && pageResultsSize > 0) {
      
      pageWithIndexAndSize = PageRequest.of(pageIndex, pageResultsSize);
    }
    
    Page<OptionalCourse> pageData = optionalCourseRepository.findOptionalSubjectPagesByStudentId(studentId, pageWithIndexAndSize);
    
    List<OptionalCourse> pageDataList = pageData.toList();

    pageDataList.forEach(course -> {

          OptionalCourse oc = course;

          //When trying to fetch student info from optional course, when student info is not there then we are getting below error
          oc.getStudent(); **//com.sun.jdi.InvocationException: Exception occurred in target VM occurred invoking method hibernate & org.hibernate.LazyInitializationException: could not initialize proxy [com.xxx.xxx.Student#550] - no Session**
    });
}

事务性的服务方法:

@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public List<CustomBeanClass> retrieveRpdLogRequestsList(Integer studentId, Integer pageIndex, Integer pageResultsSize) {

    Pageable pageWithIndexAndSize = Pageable.unpaged();
    
    if(Objects.nonNull(pageIndex) && Objects.nonNull(pageResultsSize) && pageIndex >= 0 && pageResultsSize > 0) {
      
      pageWithIndexAndSize = PageRequest.of(pageIndex, pageResultsSize);
    }
    
    Page<OptionalCourse> pageData = optionalCourseRepository.findOptionalSubjectPagesByStudentId(studentId, pageWithIndexAndSize);
    
    List<OptionalCourse> pageDataList = pageData.toList();

    pageDataList.forEach(course -> {

          OptionalCourse oc = course;

          //When trying to fetch student info from optional course, when student info is not there then we are getting below error
          oc.getStudent(); **// EntityNotFoundException - Its trying to fetch the dependent entity student here**
    });
}

即使我使用了 LEFT JOIN FETCH,为什么当我调用依赖实体(即)oc.getStudent();生成的查询具有正确的语法为 LEFT OUTER JOIN,在 SQLDeveloper 中它给出了预期的结果。我们正在使用 Oracle 数据库。

我犯了什么错误?我不被允许使用 EAGER FETCH 策略。请通过 Lazy Fetch 本身帮助解决此问题。提前谢谢!!!!

【问题讨论】:

  • 有人可以帮忙解决上述问题吗!!!

标签: spring-boot hibernate jpa orm spring-data-jpa


【解决方案1】:

我猜你正在使用在 Spring 中默认启用的 OSIV(视图中打开会话)反模式?这是该方法的常见问题。问题是您的第一级缓存(持久性上下文)包含具有学生字段未初始化代理的实体。现在,即使您再次选择该实体并加入 fetch 关联,Hibernate 也不会替换该对象,因为它必须保留对象身份并且也不会替换代理。要解决这个问题,您必须在使用 EntityManager.clear() 进行查询之前清除持久性上下文

【讨论】:

  • 在我们的项目中,我们只保留了 spring.jpa.open-in-view=false。
  • 在进行查询之前您是否尝试运行EntityManager.clear()
  • 会尽力让您知道。谢谢!!
猜你喜欢
  • 2018-11-01
  • 2021-12-19
  • 1970-01-01
  • 2017-01-18
  • 2018-12-04
  • 2016-08-13
  • 2018-12-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多