残念ながら、ここでは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プロバイダーが知る限り、これはテーブルであり、データを読み取るために必要なクエリをサポートします。
ただし、挿入はサポートされません。現在データベースにない所有者の電話を追加する必要がある場合は、後ろを回って電話
に直接行を挿入する必要があります。 。あまり良くありません。