JPA left join查询不会在Spring Boot中实例化子集合吗?

JPA left join查询不会在Spring Boot中实例化子集合吗?,jpa,spring-boot,java-8,spring-data,Jpa,Spring Boot,Java 8,Spring Data,只是一个简单的问题,我正在使用JPA和spring boot。我有一个类成员与类艺术家有@manytomy(FetchType.LAZY)关系。会员不需要有艺术家,但艺术家需要有会员 在我的JpaRepository扩展中,我有一个方法来获取成员和它可能拥有的任何可能的艺术家子女。看起来像这样: @Query("select m from Member m left join fetch m.artists where m.id=:id") Member getMemberWithArtists

只是一个简单的问题,我正在使用JPA和spring boot。我有一个类成员与类艺术家有@manytomy(FetchType.LAZY)关系。会员不需要有艺术家,但艺术家需要有会员

在我的JpaRepository扩展中,我有一个方法来获取成员和它可能拥有的任何可能的艺术家子女。看起来像这样:

@Query("select m from Member m left join fetch m.artists where m.id=:id")
Member getMemberWithArtists(@Param("id") long memberId);
在A没有B子级的情况下,B集合返回为null。 我以前在JavaEE项目中使用过这种方法,然后这种查询总是给我一个空集合,而不是空集合。spring boot的处理方式是否有所不同

我的问题是,我能做些什么使它返回一个空集合而不是null

这里是实体A

@Entity
@Table(name="MEMBER")
public class Member extends LocationHolder implements Messenger {

    @ManyToMany(cascade={CascadeType.MERGE,CascadeType.REFRESH}, fetch=FetchType.LAZY)
    @JoinTable(name="MEMBER_ARTIST_REL", 
       joinColumns=@JoinColumn(name="MEMBER_ID", referencedColumnName="ENTITY_ID"), 
       inverseJoinColumns=@JoinColumn(name="ARTIST_ID", referencedColumnName="ENTITY_ID"))
    private List<Artist> artists;
@实体
@表(name=“MEMBER”)
公共类成员扩展LocationHolder实现Messenger{
@ManyToMany(cascade={CascadeType.MERGE,CascadeType.REFRESH},fetch=FetchType.LAZY)
@JoinTable(name=“MEMBER\u ARTIST\u REL”,
joinColumns=@JoinColumn(name=“MEMBER\u ID”,referencedColumnName=“ENTITY\u ID”),
inverseJoinColumns=@JoinColumn(name=“ARTIST\u ID”,referencedColumnName=“ENTITY\u ID”))
私人艺术家名单;
这里是B

@Entity
@Table(name="ARTIST")
public class Artist extends LocationHolder {

   @ManyToMany(mappedBy="artists", targetEntity=Member.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH})
   private List<Member> members;
@实体
@表(name=“ARTIST”)
公共级艺术家扩展位置持有者{
@ManyToMany(mappedBy=“artists”,targetEntity=Member.class,fetch=FetchType.LAZY,cascade={MERGE,REFRESH})
非公开名单成员;

@Id字段位于超类中,类型为Long

默认情况下,在您描述的场景中,JPA确实应该返回一个空集。但是,查看您的实体,我怀疑存在可能导致
null
结果的场景:

  • 创建成员时,您的实体似乎没有将
    艺术家
    列表初始化为空集合
  • 创建并保存
    成员的实例
  • 如果在相同的JPA会话中您尝试使用
    getMemberWithArtists
    存储库方法加载
    成员
    ,那么实际上,
    member.artists
    集合将为
    null
    。这是由于
    成员
    实例是从JPA会话缓存返回的(由于缺少集合的默认初始化,在步骤(2)中创建的
    member.artists
    等于
    null
  • 我已经尝试在下面的代码片段中说明了这一点:

    
    
        @Test
        public void testNullCollection() {
                Member member = new Member();
                memberRepository.save(member);
                member = memberRepository.getMemberWithArtists(member.getId());
                // Here the collection is going to be null since the instance is returned from the session cache
                assertNull(member.getArtists());
                entityManager.flush();
                entityManager.clear();
                // Here the collection is going to be empty, since in the previous step the session was cleared hence forcing JPA to initialize the entity from scratch and inject lazy collection
                member = memberRepository.getMemberWithArtists(member.getId());
                assertNotNull(member.getArtists());
                assertTrue(member.getArtists().isEmpty());
            }
    
    
    这个集成测试实际上对我来说是通过的。(如果测试JPA会话跨越整个测试。在实际的web应用程序中,您应该将JPA会话配置为仅持续一个请求)

    我认为,只要将
    成员.artists
    初始化为
    成员
    实体构造函数中的空集合,就可以解决新创建和持久化实体的问题(在相同JPA会话中加载时)


    希望这能有所帮助。

    似乎有点奇怪,请您也发布类
    A
    B
    的代码。刚刚用完整的类名编辑了问题,刚刚用您的类尝试过,返回的是空集而不是
    null
    。但是,有一个问题,您是否在相同的JPA ses中执行查询创建
    成员
    的sion(例如,在集成测试中)?如果是,请发布包含测试的代码好吗?谢谢你的帮助,Ruben,初始化集合解决了这个问题。但是,这是一件好事吗?我很早就决定不初始化集合,因为这会导致大量分配内存的浪费。在我是需要t?还是我在这里过于雄心勃勃?我对JPA不太了解,所以请让我知道。欢迎:-)。嗯,老实说,除非您有严格的要求,否则我不会为额外的内存花费太多。但是,您也可以将集合的初始化推迟到实际访问为止(延迟初始化),例如,在
    getArtists()中添加
    null
    检查和默认初始化例程
    方法。只要集合的所有访问都通过
    getArtists()
    进行,您就可以享受这两个好处:应用程序的其余部分不知道集合可能为
    null
    ;在访问集合之前,您不会浪费内存。好的,很高兴知道,我会采用这种方法。感谢您花时间提供帮助!
    
    
        public Member() {
            this.artists = new ArrayList();
        }