sql >> データベース >  >> RDS >> PostgreSQL

ElementCollectionを使用したJPAマッピングの複数行

    残念ながら、ここでは1つのテーブルしか保持しないというわずかな違いが問題だと思います。

    PhoneIdの宣言を見てください クラス(私が提案するのは PhoneOwnerと呼ばれる方が良いでしょう またはそのようなもの):

    @Entity
    @Table(name="Phones")
    public class PhoneId {
    

    クラスが特定のテーブルにマップされたエンティティであると宣言すると、一連のアサーションが作成されます。ここでは、そのうちの2つが特に重要です。まず、エンティティのインスタンスごとにテーブルに1つの行があり、その逆も同様です。次に、エンティティのスカラーフィールドごとにテーブルに1つの列があり、その逆も同様です。これらは両方とも、オブジェクトリレーショナルマッピングのアイデアの中心です。

    ただし、スキーマでは、これらのアサーションはどちらも当てはまりません。あなたが提供したデータ:

    OWNER_ID    TYPE      NUMBER
      1         home      792-0001
      1         work      494-1234
      2         work      892-0005
    

    owner_idのエンティティに対応する2つの行があります 1、最初の主張に違反します。 TYPE列があります およびNUMBER エンティティ内のフィールドにマップされておらず、2番目のアサーションに違反しています。

    (明確にするために、 Phoneの宣言に問題はありません。 クラスまたはphones フィールド-PhoneIdのみ エンティティ)

    その結果、JPAプロバイダーが PhoneIdのインスタンスを挿入しようとしたとき データベースに入ると、問題が発生します。 TYPEのマッピングがないため およびNUMBER PhoneIdの列 、挿入用のSQLを生成するとき、それらの値は含まれません。これが、表示されるエラーが発生する理由です。プロバイダーは INSERT INTO Phones(owner_id)VALUES(?)を書き込みます。 、PostgreSQLは INSERT INTO Phones(owner_id、type、number)VALUES(?、null、null)として扱います 、拒否されます。

    このテーブルに行を挿入できたとしても、そこからオブジェクトを取得する際に問題が発生します。 PhoneIdのインスタンスを要求したとします owner_idを使用 1.プロバイダーは、owner_id =1の電話からselect*に相当するSQLを記述します。 、およびオブジェクトにマップできる行を1つだけ見つけることが期待されます。ただし、2つの行が見つかります!

    恐れ入りますが、解決策は2つのテーブルを使用することです。1つは PhoneId用です。 、および Phone用に1つ 。 PhoneIdのテーブル 簡単ですが、JPAマシンを正しく動作させるために必要です。

    PhoneIdの名前を変更するとします PhoneOwnerへ 、テーブルは次のようになっている必要があります:

    create table PhoneOwner (
        owner_id integer primary key
    )
    
    create table Phone (
        owner_id integer not null references PhoneOwner,
        type varchar(255) not null,
        number varchar(255) not null,
        primary key (owner_id, number)
    )
    

    (owner_id、number)を作成しました 電話の主キー 、1人の所有者が特定のタイプの複数の番号を持っている可能性があるが、2つのタイプの下で1つの番号が記録されることは決してないという前提で。 (owner_id、type)をお勧めします それがあなたのドメインをよりよく反映しているなら。)

    その場合、エンティティは次のようになります。

    @Entity
    @Table(name="PhoneOwner")
    public class PhoneOwner {
        @Id
        @Column(name="owner_id")
        long id;
    
        @ElementCollection
        @CollectionTable(name = "Phone", joinColumns = @JoinColumn(name = "owner_id"))
        List<Phone> phones = new ArrayList<Phone>();
    }
    
    @Embeddable
    class Phone {
        @Column(name="type", nullable = false)
        String type;
        @Column(name="number", nullable = false)
        String number;
    }
    

    さて、本当に PhoneOwnerのテーブルを導入したくない場合 、その後、ビューを使用してそれから抜け出すことができるかもしれません。このように:

    create view PhoneOwner as select distinct owner_id from Phone;
    

    JPAプロバイダーが知る限り、これはテーブルであり、データを読み取るために必要なクエリをサポートします。

    ただし、挿入はサポートされません。現在データベースにない所有者の電話を追加する必要がある場合は、後ろを回って電話に直接行を挿入する必要があります。 。あまり良くありません。




    1. オブジェクトに関するphpyiiフレームワークの問題(2)

    2. PHPのin_arrayとMySQLSELECT

    3. 選択と更新の間の競合状態

    4. テーブルに挿入しようとしたときに「ORA-00922:オプションがないか無効です」