Spring JPA双向@ManyToOne不';行不通

Spring JPA双向@ManyToOne不';行不通,spring,spring-boot,jpa,spring-data-jpa,Spring,Spring Boot,Jpa,Spring Data Jpa,我们用双向@manytone关系链接了两个实体,如下所示: @Entity @Setter @Getter @Builder @NoArgsConstructor @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Foo { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @OneToMa

我们用双向@manytone关系链接了两个实体,如下所示:

@Entity
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Foo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "foo")
    private Set<Bar> bars;
}

@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Bar {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "foo_id")
    private Foo foo;
}
@实体
@塞特
@吸气剂
@建筑商
@诺尔格构装师
@AllArgsConstructor(access=AccessLevel.PRIVATE)
公开课Foo{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
私人长id;
@OneToMany(fetch=FetchType.LAZY,mappedBy=“foo”)
私人酒吧;
}
@实体
@吸气剂
@塞特
@建筑商
@诺尔格构装师
@AllArgsConstructor(access=AccessLevel.PRIVATE)
公共类酒吧{
@身份证
@GeneratedValue(策略=GenerationType.IDENTITY)
私人长id;
@许多酮
@JoinColumn(name=“foo\u id”)
私人富福;
}
当我创建Foo实体和Bar实体,并尝试将创建的Foo设置为Bar时,更改不会反映在另一侧

以下是我的集成测试的代码:

Foo foo = fooRepository.save(Foo.builder()...build());

Bar bar = new Bar();
bar.setFoo(foo);
bar.set...();
barRepository.save(bar);

Foo updatedFoo = fooRepository.findById(foo.getId()).get();
List<Bar> bars = updatedFoo.getBars(); // this is null
Foo-Foo=fooRepository.save(Foo.builder()…build());
条形=新条形();
巴.塞富(富);
酒吧设置…();
barRepository.save(bar);
Foo updatedFoo=fooRepository.findById(Foo.getId()).get();
列表栏=updatedFoo.getBars();//这是空的
我不知道为什么fetched foo中的条为空。当我尝试从存储库中获取给定的条时,我可以在这一侧看到保存的Foo。

简短回答
  • JPA要求您设置关系的双方
  • 只要您设置了拥有方
    bar.setFoo()
    ,数据库就会随着关系的更改而更新因此您的数据库是正确的
  • 非拥有方
    foo
    仅在手动设置时反映数据库中的内容,或强制刷新或重新加载,例如
    entityManager.refresh(foo)
注释

  • 在事务会话中,对存储库的每个调用都不会转换为数据库调用。由于hibernate all ready在第1行中将
    foo
    作为
    managed
    实体, 调用时,
    fooRepository.findById(foo.getId()).get()JPA不发出select语句如果您搜索
    事务性写在后面
    可重复读取
    ,您可以找到更多信息

  • Foo-Foo=fooRepository.save(Foo.builder()…build())
    -
    foo
    成为托管实体,由于
    可重复读取
    保证,JPA将为
    foo
    的所有后续检索返回相同的
    foo

  • 如果在保存后调用
    fooRepository.findById(fooId)
    ,它甚至不会进入数据库

  • barRepository.save(bar)-
    条形图
    也会被管理

  • foo
    bar
    都是托管实体,但是foo说我没有任何
    bar
    s,bar说我知道一个
    foo
    ,因为你没有设置
    foo.getbar().add(bar)
    。这在内存中是不正确的,因为您必须显式地设置关系的两侧

  • 如果您完成当前的
    transactional方法
    ,而不将条形图添加到foo中,然后在另一个transactional中调用
    fooRepository.findById(fooId)
    ,它将向您显示它获取foo和条形图

更多参考资料


您是否尝试将级联添加到映射中

@OneToMany(fetch = FetchType.LAZY, mappedBy = "foo",cascade= CascadeType.ALL)
private Set<Bar> bars;

@ManyToOne(cascade= CascadeType.ALL)
@JoinColumn(name = "foo_id")
private Foo foo;
barRepository.save(bar)将不会持久保存foo


添加cascade时,它将保留这两个实体,或者您需要使用fooRepository手动保存foo实体。

是的,使用@Transactional,您可以尝试初始化集合即私有集合栏;=新HashSet();并删除fetch。
Foo foo = fooRepository.save(Foo.builder()...build());

Bar bar = new Bar(); 
bar.setFoo(foo);
bar.set...();
barRepository.save(bar);