[JAVA] Fügen Sie @ManyToOne zu einem Teil des zusammengesetzten Primärschlüssels in Hibernate JPA hinzu

Diesmal Zeitfenster (≒ Tagebuch)

=> Ja, verwenden wir den zusammengesetzten Primärschlüssel

Tabellenbeispiel

Zum Beispiel in MySQL eine solche Tabelle

CREATE TABLE parent(
  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  bar VARCHAR(30) NOT NULL
);

CREATE TABLE parent_child(
  parent_id INT NOT NULL,
  value_ VARCHAR(30) NOT NULL,

  PRIMARY KEY(parent_id, value_),
  FOREIGN KEY(parent_id) REFERENCES parent(id)
);

ChildEntity Da es sich um einen zusammengesetzten Primärschlüssel handelt, verwenden wir "@ EmbeddedId", aber der Verweis auf die übergeordnete Entität mit "@ ManyToOne" sollte sich im Feld der äußeren Entitätsklasse anstelle der PK-Klasse __ befinden. [^ 1] [^ 1]: StackOverflowError tritt während des Lesevorgangs auf, wenn die PK-Klasse ein Feld für "@ ManyToOne" hat.

Durch Hinzufügen von "@ MapsId" zusammen mit "@ ManyToOne" wird die ID auf der Seite der übergeordneten Tabelle zugewiesen, wenn Eltern und Kind gleichzeitig eingefügt werden. Im Fall der untergeordneten Aktualisierung der untergeordneten Aktualisierung wird dies jedoch nicht erledigt, sodass Sie die übergeordnete und die übergeordnete ID selbst synchronisieren müssen.

ChildEntity.java


@Entity
@Table(name = "parent_child")
@ToString(exclude = "parent")
@NoArgsConstructor
public class ChildEntity {
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class PK implements Serializable {
        @Column(name = "parent_id")
        private int parentId;

        @Column(name = "value_")
        private String value;
    }

    @EmbeddedId
    @Getter
    @Setter
    private PK pk;

    @ManyToOne
    @JoinColumn(name = "parent_id", referencedColumnName = "id")
    @MapsId("parentId")
    @Getter
    @Setter
    private ParentEntity parent;

    public ChildEntity(@NonNull final ParentEntity parent,
            @NonNull final String value) {
        this.pk = new PK(parent.getId(), value);
        this.parent = parent;
    }

    public void setParent(@NonNull final ParentEntity parent) {
        this.pk.setParentId(parent.getId());
        this.parent = parent;
    }
}

Beachten Sie, dass die unachtsame Verwendung von lombok.ToString, lombok.EqualsAndHashCode, Jackson usw. eine Endlosschleife verursacht, da Eltern und Kind Zirkelverweise sind.

ParentEntity Die übergeordnete Seite unterscheidet sich nicht von der normalen "@ OneToMany" (bei Verwendung von Ersatzschlüsseln).

ParentEntity.java


@Entity
@Table(name = "parent")
@Data
public class ParentEntity {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @OneToMany(mappedBy = "parent", orphanRemoval = true, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Fetch(FetchMode.SUBSELECT)
    private List<ChildEntity> children;

    @Column(name = "bar")
    private String bar;
}

Beachten Sie, dass der untergeordnete Datensatz nicht gelöscht wird, wenn Sie orphanRemoval nicht im Parameter "@ OneToMany" festlegen, auch wenn Sie das untergeordnete Element auf der übergeordneten Seite löschen. Wenn Sie "@Fetch (FetchMode.SUBSELECT)" nicht hinzufügen, tritt das N + 1-Problem auf.

SQL wurde zum Zeitpunkt der Aktualisierung ausgegeben

Hibernate 5.0.12 sieht so aus. Beim Einfügen der neu hinzugefügten ChildEntity befürchte ich, dass sie einzeln getrennt von der zusammen mit ParentEntity erfassten Liste ausgewählt wird. Für die Elemente, die sich nicht geändert haben, reicht der EAGER-Abruf aus, daher frage ich mich, ob es in diesem Projekt ein Problem gibt.

select parententi0_.id as id1_0_0_, parententi0_.bar as bar2_0_0_, children1_.parent_id as parent_i1_1_1_, children1_.value_ as value_2_1_1_, children1_.parent_id as parent_i1_1_2_, children1_.value_ as value_2_1_2_ from parent parententi0_ left outer join parent_child children1_ on parententi0_.id=children1_.parent_id where parententi0_.id=?
binding parameter [1] as [INTEGER] - [5]
select childentit0_.parent_id as parent_i1_1_0_, childentit0_.value_ as value_2_1_0_ from parent_child childentit0_ where childentit0_.parent_id=? and childentit0_.value_=?
binding parameter [1] as [INTEGER] - [5]
binding parameter [2] as [VARCHAR] - [0.42733237750132513]
insert into parent_child (parent_id, value_) values (?, ?)
binding parameter [1] as [INTEGER] - [5]
binding parameter [2] as [VARCHAR] - [0.42733237750132513]
delete from parent_child where parent_id=? and value_=?
binding parameter [1] as [INTEGER] - [5]
binding parameter [2] as [VARCHAR] - [0.8694858141499555]

Recommended Posts

Fügen Sie @ManyToOne zu einem Teil des zusammengesetzten Primärschlüssels in Hibernate JPA hinzu
zusammengesetzter Schlüssel für den Ruhezustand
Bis zur Verwendung von Spring Data und JPA Part 2
Bis zur Verwendung von Spring Data und JPA Part 1
Generieren Sie mit TableGenerator of Hibernate (JPA) eine Seriennummer und speichern Sie diese in der ID von String.
Fassen Sie die wichtigsten Punkte für den Einstieg in JPA zusammen, die Sie mit Hibernate gelernt haben
Besiege den Aufwand, C-Arrays von Swift als Tupel zu behandeln
So erhalten Sie die ID des automatisch inkrementierten PRIMAY-Schlüssels in MyBatis