有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何使用带@OneToOne关系的fetch join?

我有实体贴子,贴子细节。 这些是一对一的关系,PostDetail是可选的

class Post {
    @Id
    private int id;

    @Column
    private String title;

    @Column
    private Strint contents;

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private PostDetail postDetail;
}

class PostDetail {
    @Id
    private int id;

    @Column
    private boolean duplicated;

    @OneToOne
    private Post post;
}

public interface PostRepository extends JpaRepository<Post, Integer> {
    @Transactional
    @Query("SELECT a FROM Post a LEFT JOIN FETCH a.postDetail")
    public Page<Post> getAll(Example<Post> example, Pageable pageable);

    @Transactional
    @Query("SELECT a FROM Post a LEFT JOIN FETCH a.postDetail")
    public List<Post> getAll();
}

当应用程序启动时,会发生异常

Caused by: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list ...

有什么问题吗?我尝试这样做是为了避免在查询帖子列表(getAll())时出现N+1问题


抱歉,我修改了我的问题

这两种PostRepository方法都会出错

第一个getAll()抛出错误“查询指定的联接获取…”

第二个getAll()抛出错误

org.mariadb.jdbc.internal.common.QueryException: Unknown column 'postdetail1_.post_id' in 'field list'


共 (2) 个答案

  1. # 1 楼答案

    如果想避免1+N查询问题,可以使用EntityGraph。只需在自定义Repo中重写'findAll'方法,并对其使用EntityGraph注释,如下所示:

    public interface PostRepository extends JpaRepository<Post, Integer> {
    
        @Override
        @EntityGraph(attributePaths = {"postDetail"})
        Page<Post> findAll(Pageable pageable);
    
        @Override
        @EntityGraph(attributePaths = {"postDetail"})
        List<Post> findAll();
    }
    
  2. # 2 楼答案

    因为您正在使用Spring Data JPA,所以Postid的类型应该与JpaRepository<T, ID extends Serializable>中的ID一致,只需做一些修改:

    @Entity
    @Table(name = "post")
    class Post {
        @Id
        private Integer id;
    
        @Column
        private String title;
    
        @Column
        private String contents;
    
        @OneToOne(cascade = CascadeType.ALL)
        @JoinColumn(name = "postDetail_id")//assume this is the name
        private PostDetail postDetail;
    }
    

    您不必为getAll()定义查询,Spring Data JPA为常见查询提供了一些嵌入式实现,只需调用它们:

    public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
    
        <S extends T> S save(S entity); 
    
        T findOne(ID primaryKey);       
    
        Iterable<T> findAll();          
    
        Long count();                   
    
        void delete(T entity);          
    
        boolean exists(ID primaryKey);  
    
        // … more functionality omitted.
    }
    

    所以PostRepository就像:

    public interface PostRepository extends JpaRepository<Post, Integer> {
    
    }
    

    然后可以在单元测试中测试它:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class MyTest {
    
        @Autowired
        private PostRepository repo;
    
        @Test
        public void testFindAll(){
            repo.findAll();
        }
    
        @Test
        public void testFindById(){
            repo.findOne(id);
        }
    }