ヌル可能にしたい多対1の関係があります。
_@ManyToOne(optional = true)
@JoinColumn(name = "customer_id", nullable = true)
private Customer customer;
_
残念ながら、JPAは私のデータベースの列をNOT NULLとして設定し続けます。誰かこれを説明できますか?それを機能させる方法はありますか? JBoss 7、永続化プロバイダーとしてのHibernateとJPA 2.0、およびPostgreSQL 9.1データベースを使用していることに注意してください。
[〜#〜]編集[〜#〜]:
問題の原因を見つけました。どうやら、参照先のエンティティCustomer
で主キーを定義した方法が原因です。
_@Entity
@Table
public class Customer {
@Id
@GeneratedValue
@Column(columnDefinition="serial")
private int id;
}
_
主キーに@Column(columnDefinition="serial")
を使用すると、それを参照する外部キーがデータベースで_NOT NULL
_に自動的に設定されるようです。列のタイプをserial
と指定した場合、これは実際に予期される動作ですか?この場合、null許容の外部キーを有効にするための回避策はありますか?
前もって感謝します。
私は自分の問題の解決策を見つけました。エンティティCustomer
で主キーを定義する方法は問題ありませんが、問題は外部キー宣言にあります。次のように宣言する必要があります。
@ManyToOne
@JoinColumn(columnDefinition="integer", name="customer_id")
private Customer customer;
実際、属性columnDefinition="integer"
は省略されます。外部キーはデフォルトでソース列として設定されます。独自のシーケンスを持つnull以外のシリアルです。もちろん、新しいIDを作成するのではなく、自動インクリメントされたIDを参照するだけなので、これは望ましいことではありません。
また、属性name=customer_id
も必要です。いくつかのテストを実行するときに観察しました。それ以外の場合、外部キー列は引き続きソース列として設定されます。これは私の考えでは奇妙な行動です。これを明確にするコメントまたは追加情報は大歓迎です!
最後に、このソリューションの利点は、IDが(JPAではなく)データベースによって生成されるため、手動で、またはデータの移行やメンテナンスで頻繁に発生するスクリプトを介してデータを挿入するときに、その心配をする必要がないことです。
私はこの問題に遭遇しましたが、この方法で解決することができました:
_@ManyToOne
@JoinColumn(nullable = true)
private Customer customer;
_
たぶん、問題は@ManyToOne(optional = true)
の宣言から生じたのかもしれません
それは非常に奇妙です。
JPAでは、nullableパラメータはデフォルトでtrueです。私はこの種の構成を常に使用しており、正常に動作します。エンティティを保存しようとすると、成功するはずです。
この関係用に作成されたテーブルを削除しようとしましたか?多分あなたはその列を持つレガシーテーブルを持っていますか?
または、これは適切な構成であるため、他のコードのチャンクで解決策を見つける必要があります。
注:JPA2とHibernateを使用してPostgreSQLでこの構成を試しました。
[〜#〜]編集[〜#〜]
その場合、主キーの定義を少し変えることができます。
たとえば、次のような定義を使用できます。
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column()
private Long id;
そしてpostgresqlは生成されます
id bigint NOT NULL
-- with constraint
CONSTRAINT some_table_pkey PRIMARY KEY (id)
これで十分であれば、この解決策を試すことができます。
トランザクション内、ただし保存操作の前に、外部キー列の値を明示的にnullに設定します。このhibernateでは、この外部キー関連のテーブルに対して選択クエリを実行しないでください。また、「フラッシュする前に一時的なインスタンスを保存する」という例外をスローしないでください。 「null値」を条件付きで設定する場合は、1を実行し、repo呼び出しget/findを使用して値をフェッチおよび設定します。次に、フェッチされた条件の値を確認し、それに応じてnullに設定します。以下のコードをテストしてテストしましたそして働いていた
//トランザクションの開始 Optional <Customer> customerObject = customerRepository.findByCustomerId(customer.getCustomerId()) if(customerObject.isPresent())yourEnclosingEntityObject。 setCustomer(customerObject)} else {yourEnclosingEntityObject.setCustomer(null)} yourEnclosingEntityObjectRepository.save(yourEnclosingEntityObject) //トランザクション終了