[DB]テーブルをデザインしましょう!2

18118 ワード

たじゅうせい


データベースに基づいて多重性を決定します.
関連付けには対称性があります.
一対多
一対一
ぴったり合った

マルチペア1(N:1)


掲示板と投稿の関係を例に挙げます.

要求


1つの掲示板(1)で複数の投稿(N)を作成できます.
1つの投稿は1つの掲示板にしか書けません.
投稿も掲示板も対日関係です.
データベースベースの多重性が決定された(投稿N:掲示板1).
これは、投稿(N)によって管理される外部キーの一般的な形式です.(データベースは、すべての(N)個の外部キーで構成されている必要があります.)
→多対一(N:1)一方向
@Entity
public class Post {
    @Id @GeneratedValue
    @Column(name = "POST_ID")
    private Long id;

    @Column(name = "TITLE")
    private String title;

    @ManyToOne
    @JoinColumn(name = "BOARD_ID")
    private Board board;
    //... getter, setter
}

@Entity
public class Board {
    @Id @GeneratedValue
    private Long id;
    private String title;
    //... getter, setter
}
「複数対1」一方向では、「複数ページPost」に@ManyToOneのみが追加されていることがわかります.
逆にBoardは参照しません.(一方的なので)
→多対一(N:1)双方向
@Entity
public class Post {
    @Id @GeneratedValue
    @Column(name = "POST_ID")
    private Long id;

    @Column(name = "TITLE")
    private String title;

    @ManyToOne
    @JoinColumn(name = "BOARD_ID")
    private Board board;
    //... getter, setter
}

@Entity
public class Board {
    @Id @GeneratedValue
    private Long id;
    private String title;

    @OneToMany(mappedBy = "board")
    List<Post> posts = new ArrayList<>();
    //... getter, setter
}
複数のペアを双方向にするには、@OneToManyを(1)ページに追加し、双方向マッピングを使用して、関連する所有者をmappedByと指定します.
mappedByとして指定すると、ターゲット変数の名前に基づいて値を指定できます.Postオブジェクト(ターゲット)のboardという変数であるため、boardとして指定されます.

1対多(1:N)


うん.一対多が多対一で反対する立場にあるので、整理する必要はありますか?前述の多対一の基準は関連関係の主人を(N)側に置くことであり,今回言及する一対多の基準は関連関係の主人を(1)側に置くことであると考えられる.

※参考までに実務では一対多(1:N)一方向はほとんど使われていません。


→一対多(1:N)一方向

データベースの観点から、すべての(N)方が外部キーを管理する必要があります。


ただし、マルチ(N)ページオブジェクト(1)ページオブジェクトを操作(作成、変更または削除)する方法.
@Entity
public class Post {
    @Id @GeneratedValue
    @Column(name = "POST_ID")
    private Long id;

    @Column(name = "TITLE")
    private String title;
  //... getter, setter
}

@Entity
public class Board {
    @Id @GeneratedValue
    private Long id;
    private String title;

    @OneToMany
    @JoinColumn(name = "POST_ID") //일대다 단방향을 @JoinColumn필수
    List<Post> posts = new ArrayList<>();
    //... getter, setter
}
@OneToManyにmappedByがありません.双方向ではないからです.
@JoinColumnを使用して結合します.
実際の使用方法は次のとおりです.
//...
Post post = new Post();
post.setTitle("가입인사");

entityManager.persist(post); // post 저장

Board board = new Board();
board.setTitle("자유게시판");
board.getPosts().add(post);

entityManager.persist(board); // board 저장
//...
上記の場合、postを保存すると挿入クエリーが表示されます.
そして問題
Boardを保存すると、Boardを挿入したクエリーが終了すると、postを更新するクエリーが表示されます.
BoardがgetPosts().add(post); 一部の原因で.
BoardエンティティはBoardテーブルにマッピングされるため、Boardテーブルに直接割り当てることができますが、PostテーブルのBOARD IDを保存できないため、クエリーの結合と更新をキャンセルする必要があります.

致命的な欠点


1日しか修正されていないようですが、他の修正があったためクエリーが発生しました.
Boardを保存したのになぜPostが修正したのですか?私にこのような考えを起こさせた.
クエリーの更新により、パフォーマンスの問題はそれほど大きくありません.
したがって,TIPを用いて1対多(1:N)の一方向関連関係マッピングを行う必要がある場合は,多対一(N:1)の双方向関連関係をマッピングするだけで,今後のメンテナンスにおいてより容易になるので,この方法を推奨する.
ただし、実際の操作で使用を禁止しない理由は、使用を避けることが望ましいためですが、代わりにJPA値タイプを使用する場合に便利です.=あまり役に立たない.

→一対多(1:N)双方向(業務使用禁止)


一対多双方向は正式に存在しないので省略します.
キーワードは@JoinColumn(updatable=false、insertable=false)ですが、1対のマルチ双方向を使用する必要がある場合は、マルチペアの双方向を使用することが望ましいです.

🌈 したがって、一対多(1:N)の一方向、双方向を使用するのではなく、多対一(N:1)の双方向使用が正しいと簡単に考えるべきである。


1対1(1:1)
プライマリ・テーブルに外部キーを配置するか、ターゲット・テーブルに外部キーを配置できます.
※一対一(1:1)なので、テーブルA、Bがある場合、Aがメインテーブルであれば、Bがターゲットテーブル、Bがメインテーブルであれば、Aがターゲットテーブルです.
→一対一(1:1)一方向
メインテーブルが持つ意味を外部キーで説明します.(Postテーブル(プライマリテーブル)に外部キー(FK)を使用したAttachテーブル(ターゲットテーブル)のPK)
投稿に添付ファイル(Attach)は1つしか添付できないと仮定します.
@Entity
public class Post {
    @Id @GeneratedValue
    @Column(name = "POST_ID")
    private Long id;

    @Column(name = "TITLE")
    private String title;
    @OneToOne
    @JoinColumn(name = "ATTACH_ID")
    private Attach attach;
    //... getter,setter
}
@Entity
public class Attach {
    @Id @GeneratedValue
    @Column(name = "ATTACH_ID")
    private Long id;
    private String name;
  //... getter, setter
}
특별할 게 없습니다.
→一対一(1:1)双方向
同じ@OneToOneとmappedByを読み取り専用に簡単に設定するだけで、双方向の操作を簡単にすることができます.
@Entity
public class Attach {
    @Id @GeneratedValue
    @Column(name = "ATTACH_ID")
    private Long id;
    private String name;

    @OneToOne(mappedBy = "attach")
    private Post post;
  //... getter, setter
}

→一対一(1:1)一方向に対応していない


先ほど整理してみましたが、なぜまた出てきたのでしょうか.今回はPostテーブル(メインテーブル)ではなくAttachテーブル(ターゲットテーブル)で外部キー(FK)を使いたい時を考えてみました.
しかしこのJPAはまったくサポートしていません
→一対一(1:1)双方向
この場合、どちらも一対一なので、上記の定義に従って処理すればよい.
しかし、論争の余地がある.
Postで外部キーを管理するか、Attachで外部キーを管理するかを考えるべきです.つまり、テーブルの上のどの位置に置くかを考えるべきです.
テーブルは、一度作成すると通常硬くなります.つまり変更が難しいということです.
しかし、業務はいつでも変わる可能性があります.
ビジネスが変化した場合、投稿に複数の添付ファイルを添付できます.状況はどうなりますか?
その後、すべての(N)ページのAttachテーブルに外部キーがあり、変更に柔軟です.
では、確率が(N)のテーブルの上に外キーを置くときっといいですか?
それは違います.
オブジェクトの観点から、Post(1)に外部キーがある場合、PostをクエリーするたびにAttachの参照があるため、パフォーマンスが向上します.
※結論
総合的な判断と意思決定が必要ですが、一対一の決定にも慎重であると簡単に仮定すると、プライマリ・テーブルに外部キーを配置したほうがいいです.
もう一度言いますが、これは議論のある意見にすぎません.

マルチペアマルチ(N:N)


業務使用禁止
これは、中間テーブルが非表示であるため、無意識に複雑な結合クエリーが発生する可能性があります.
ほとんどの自動生成された中間テーブルには、2つのオブジェクトのテーブルの外部キーしか格納されていないため、問題が発生する可能性があります.JPAを使用する場合、中間テーブルには通常、キー以外の情報が含まれているため、1対多、多対一の多対多(中間テーブルをエンティティとして作成)の後続の変更を柔軟に処理できます.
出典:https://jeong-pro.tistory.com/231[基本功を積むアマチュアコードブログ]