@OneToMany 关系的反转 JPA 结果

问题描述 投票:0回答:1

我将把我的问题分成3部分:

  1. JPA 实体
  2. 当前数据库设置
  3. 问题

1. JPA 实体

@Entity
@Table(name = "foo")
public class Foo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false, unique = true)
    private Long id;
    
    // ... other fields

    @OneToMany(mappedBy = "fooer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Bar> barInfo = new ArrayList<>();

    @OneToMany(mappedBy = "fooing", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Bar> baringInfo = new ArrayList<>();
}

酒吧


@Entity
@Table(name = "bar")
public class Bar {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false, unique = true)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "fooer_id", referencedColumnName = "id", nullable = false,
                foreignKey = @ForeignKey(name = "bar_fooer_id_fkey"))
    private Foo fooer;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "fooing_id", referencedColumnName = "id", nullable = false,
                foreignKey = @ForeignKey(name = "bar_fooing_id_fkey"))
    private Foo fooing;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "baz_id", referencedColumnName = "id", nullable = false,
                foreignKey = @ForeignKey(name = "bar_baz_id_fkey"))
    private Baz baz;
}

巴兹

@Entity
@Table(name = "baz")
public class Baz {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false, unique = true)
    private Long id;
    
    // ... other fields
}

2.当前数据库设置

DDL

CREATE TABLE some_schema.bar
(
    id        int8 GENERATED BY DEFAULT AS IDENTITY ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1 NO CYCLE) NOT NULL,
    fooer_id  int8 NOT NULL,
    fooing_id int8 NOT NULL,
    baz_id    int8 NOT NULL,
    CONSTRAINT bar_id_key UNIQUE (id),
    CONSTRAINT bar_fooer_id_fkey FOREIGN KEY (fooer_id) REFERENCES some_schema.foo (id),
    CONSTRAINT bar_fooing_id_fkey FOREIGN KEY (fooing_id) REFERENCES some_schema.foo (id),
    CONSTRAINT bar_baz_id_fkey FOREIGN KEY (baz_id) REFERENCES some_schema.baz (id)
);

3.问题

假设我们有两个

Foo
类型的实体(John[id=111] 和 Alice[id=222])和一个
Baz
类型的实体(Paperwork[id=999])。 John 想向 Alice 请求与 文书工作 相关的帮助。我当前对上面解释的添加请求的实现如下所示:

final var john = getById(contextId); // fooing
final var alice = getById(id);       // fooer
final var paperwork = bazService.getBazById(bazId);

john.getBarInfo()
    .add(Bar.builder()
            .fooer(alice)
            .fooing(john)
            .baz(paperwork)
            .build());

fooRepository.save(john); // <-- Here john have barInfo with values set above and baringInfo empty which is what we want

bar
中的数据如下所示:

id fooer_id fooing_id baz_id
1 222 111 999

从当前实施和要求的角度来看,这看起来还不错。 但是问题在于检索实体和类型为

Foo
的实体。

通过 ID 或整个列表检索

预期结果:

{
  "John": {
    "barInfo": {
      "fooers": [
        {
          "foo_id": 222,
          "baz_id": 999
        }
      ],
      "fooing": []
    }
  },
  "Alice": {
    "barInfo": {
      "fooers": [],
      "fooing": [
        {
          "foo_id": 111,
          "baz_id": 999
        }
      ]
    }
  }
}

实际结果:

{
  "John": {
    "barInfo": {
      "fooers": [],
      "fooing": [
        {
          "foo_id": 111,
          "baz_id": 999
        }
      ]
    }
  },
  "Alice": {
    "barInfo": {
      "fooers": [
        {
          "foo_id": 222,
          "baz_id": 999
        }
      ],
      "fooing": []
    }
  }
}

上面显示的数据是实体的伪表示

Foo
从 Spring 存储库检索(未包装到其他对象)

fooing
/
fooers
似乎颠倒了(我认为实体之间的关联有问题),我想知道我的方法是否存在一些缺陷。任何建议将不胜感激。


项目中使用的版本:

  • Spring Boot 3.2.2
  • Java 17
java spring-boot hibernate jpa spring-data-jpa
1个回答
0
投票

想通了!

我所要做的就是反转

mappedBy
参数
Foo
:

@Entity
@Table(name = "foo")
public class Foo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false, unique = true)
    private Long id;
    
    // ... other fields

    @OneToMany(mappedBy = "fooing", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
                          ~~~~~~~~
    private List<Bar> barInfo = new ArrayList<>();

    @OneToMany(mappedBy = "fooer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
                          ~~~~~~~
    private List<Bar> baringInfo = new ArrayList<>();
}

在与添加请求相关的服务中,而不是添加到

barInfo
baringInfo
列表中,我们应该刚刚保存新的
Bar
,它将与相应的实体相关联:

final var john = getById(contextId); // fooing
final var alice = getById(id);       // fooer
final var paperwork = bazService.getBazById(bazId);
final var bar = Bar.builder()
                   .fooer(alice)
                   .fooing(john)
                   .baz(paperwork)
                   .build();
barRepository.save(bar);

检索有关

Foo
的信息给出了我的问题中提到的预期结果。

© www.soinside.com 2019 - 2024. All rights reserved.