1

以前は @PrimaryKeyJoinColumn が機能していましたが、今はスプリング ブートを試していますが、何が足りないのかわかりません。すべてを正しく行ったように見えるので、非常に奇妙です。

人物クラス :

    @Table(name = "PERSON")
@Entity

@Getter
@Setter
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private Long id;


    @Column(name = "NAME")
    private String name;

    @OneToOne(cascade = CascadeType.PERSIST)
    @PrimaryKeyJoinColumn
    private Department department;
}

部門クラス :

    @Table(name = "DEPARTMENT")
@Entity
@Getter
@Setter
public class Department {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private Long id;

    @Column(name = "NAME")
    private String name;


    @OneToOne(mappedBy = "department")
    private Person person;
}

サービスクラス:

   @Transactional
    public void addPerson() {
        Person person = new Person();
        person.setName("person 1");
        Department department = new Department();
        department.setName("test");
        department.setPerson(person);
        person.setDepartment(department);
        personRepository.save(person);
    }

それは私が DB で取得するものです: Person テーブル:

ID   Name
13  person 1

部門表:

ID  Name
18  test

望ましい出力: 両方の ID が同一である必要があります (個人 ID は 13 ではなく 18 である必要があります)。


更新: hibernate は常に ID なしで Person を挿入しようとするため、Person ID から自動インクリメントを削除し、既存の部門を持つ人を挿入しようとすると、次のようになります。

Hibernate: insert into person (name) values (?)

Field 'id' doesn't have a default value

更新 2: @PrimaryKeyJoinColumn は ID 生成を部門クラスとして処理しないようです。そのため、ジェネレーターを使用する必要があります。サブクラスのIDを何もせずに結合した継承で同じアノテーションが機能するのだろうか。したがって、 ID 生成が Inheritance Joined で機能する理由を説明する答えを期待していますが、 OneToOne にはジェネレーターが必要です

4

1 に答える 1

1

部門全体を 1 人だけで構成するのは少なくとも悪い名前ですが (部門は通常、多くの人をグループ化します)、共有 PRIMARY KEY との OneToOne 関係を本当に探していると思います。

最良の解決策 (最適なメモリ、速度、およびメンテナンス) は、次を使用すること@MapsIdです。

@Getter
@Setter
@Entity
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToOne(mappedBy = "person", fetch = FetchType.LAZY)
    private Department department;
}

@Getter
@Setter
@Entity
public class Department {
    @Id // Note no generation
    private Long id;

    private String name;

    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    @JoinColumn(name = "id", foreignKey = @ForeignKey(name = "department_belongs_to_person"))
    private Person person;
}

ここで Department はリレーションを所有しており (所有とは通常、データベースに FK を持つ列があることを意味しますが、ここでは主キーを共有するだけです)、その PK を Person によって生成されたものにバインドする FK を所有しています。

関係は OneToOne、双方向であり、共有 PK が FK であることに注意してください。これはベスト プラクティスと考えられていますが、getter を 1 つ作成する必要があるという小さな欠点が 1 つあります。:)

ソース: https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/

また、このサイトの投稿を数日間読んで、いくつかのテーブルを設計する前にそれらのいくつかを実装することを強くお勧めします。:)

編集

私はここで間違っているかもしれません(今は確信しています-コメントを見てください)が、私の知る限り、IDを等しく保つことはJPAが指定するものではありません。指定できるのは基本的に次のとおりです。

「やあ、君たち (Person、Department) は兄弟 (OneToOne) であり、両方ともそれを知っています (Person エンティティの mappingBy="person" との双方向)。あなたは ID を生成する年上の仲間になります (Person は @GeneratedValue を持っています)、そしてあなたはこれらのフィールド (ID、1 つは生成され、2 番目は生成されない) を使用して接続します (@PrimaryKeyJoinColumn)。

私が言おうとしているのは、あなたが「これでつながる」と言ったからといって、それらが同期されているという意味ではないということです。

それを確実にする方法については、 @MapsId が最適であることが知られています。

別のアプローチを探している場合は、#setDepartment(Department) を使用して手動で ID を他のものと同じに設定することもできます。ここでは、部門の ID を呼び出し側の Person と同じに設定します (ただし、これは、その Person が既に ID を生成している場合にのみ機能します。これは基本的にアイデアを壊します)。

私が知っているもう1つは、外部ジェネレーター戦略を使用することです。

人:

@Id
@GeneratedValue
private long id;

@OneToOne(mappedBy="person")
private Department department;

デパートメント:

@Id
@GeneratedValue(generator="gen")
@GenericGenerator(name="gen", strategy="foreign", parameters=@Parameter(name="property", value="person"))
private long id;

@OneToOne
@PrimaryKeyJoinColumn
private Person person;

現在 - これは休止状態固有の注釈を使用しており、純粋な JPA ではありません。

于 2018-11-30T22:30:09.467 に答える