web-dev-qa-db-ja.com

@ManyToOne関係をヌル可能にすることはできません

ヌル可能にしたい多対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許容の外部キーを有効にするための回避策はありますか?

前もって感謝します。

18
vcattin

私は自分の問題の解決策を見つけました。エンティティCustomerで主キーを定義する方法は問題ありませんが、問題は外部キー宣言にあります。次のように宣言する必要があります。

@ManyToOne
@JoinColumn(columnDefinition="integer", name="customer_id")
private Customer customer;

実際、属性columnDefinition="integer"は省略されます。外部キーはデフォルトでソース列として設定されます。独自のシーケンスを持つnull以外のシリアルです。もちろん、新しいIDを作成するのではなく、自動インクリメントされたIDを参照するだけなので、これは望ましいことではありません。

また、属性name=customer_idも必要です。いくつかのテストを実行するときに観察しました。それ以外の場合、外部キー列は引き続きソース列として設定されます。これは私の考えでは奇妙な行動です。これを明確にするコメントまたは追加情報は大歓迎です!

最後に、このソリューションの利点は、IDが(JPAではなく)データベースによって生成されるため、手動で、またはデータの移行やメンテナンスで頻繁に発生するスクリプトを介してデータを挿入するときに、その心配をする必要がないことです。

11
vcattin

私はこの問題に遭遇しましたが、この方法で解決することができました:

_@ManyToOne
@JoinColumn(nullable = true)
private Customer customer;
_

たぶん、問題は@ManyToOne(optional = true)の宣言から生じたのかもしれません

7
oschlueter

それは非常に奇妙です。

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)

これで十分であれば、この解決策を試すことができます。

0
pedjaradenkovic

トランザクション内、ただし保存操作の前に、外部キー列の値を明示的に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)
 
 //トランザクション終了
0
stackoverflow