如何在@OneToOne关系中使用fetch join?

时间:2017-06-24 12:42:25

标签: java spring spring-data-jpa jpql

我有实体Post,PostDetail。 这些是一对一的关系,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();
}

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

  

引起:org.hibernate.QueryException:查询指定的连接提取,但是获取的关联的所有者在选择列表中不存在...

有什么问题?在查询帖子列表(getAll())时,我试图避免N + 1问题。

抱歉,我修改了我的问题。

两个PostRepository的方法都会出错。

首先getAll()抛出错误&#34;查询指定的连接提取...&#34;

第二个getAll()抛出错误

  

org.mariadb.jdbc.internal.common.QueryException:未知列&#39; postdetail1_.post_id&#39;在&#39;字段列表&#39;

2 个答案:

答案 0 :(得分:2)

如果您正在使用Spring Data JPAid中的Post类型应与ID中的JpaRepository<T, ID extends Serializable>一致,只需进行一些修改:

@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);
    }
}

答案 1 :(得分:2)

如果您想避免1 + N查询问题,可以使用EntityGraph。只需覆盖&#39; findAll&#39;自定义Repo中的方法,并在它们上使用EntityGraph注释,如下所示:

public interface PostRepository extends JpaRepository<Post, Integer> {

    @Override
    @EntityGraph(attributePaths = {"postDetail"})
    Page<Post> findAll(Pageable pageable);

    @Override
    @EntityGraph(attributePaths = {"postDetail"})
    List<Post> findAll();
}