23

null許容にしたい多対1の関係があります。

@ManyToOne(optional = true)
@JoinColumn(name = "customer_id", nullable = true)
private Customer customer;

残念ながら、JPAはデータベースの列をNOTNULLとして設定し続けます。誰かがこれを説明できますか?それを機能させる方法はありますか?永続性プロバイダーとしてHibernateを使用するJBoss7、JPA 2.0、およびPostgreSQL9.1データベースを使用していることに注意してください。

編集

問題の原因を見つけました。どうやらそれは私が参照されたエンティティで主キーを定義した方法によるものですCustomer

@Entity
@Table
public class Customer { 
    @Id
    @GeneratedValue
    @Column(columnDefinition="serial")
    private int id;
}

主キーにを使用@Column(columnDefinition="serial")すると、それを参照する外部キーNOT NULLがデータベースに自動的に設定されるようです。列タイプをとして指定するときに、これは本当に予想される動作serialですか?この場合、null許容の外部キーを有効にするための回避策はありますか?

前もって感謝します。

4

4 に答える 4

22

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

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

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

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

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

于 2013-03-24T00:59:50.003 に答える
6

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

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

たぶん問題は宣言から生じた@ManyToOne(optional = true)

于 2014-04-23T14:48:27.437 に答える
0

それはとても奇妙です。

JPAでは、null許容パラメータはデフォルトで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)

これで十分な場合は、このソリューションを試すことができます。

于 2013-03-20T15:53:15.240 に答える
0

トランザクション内で、保存操作の前に、外部キー列の値を明示的にnullに設定します。この休止状態では、この外部キー関連テーブルに対してselectクエリを実行しないでください。また、「フラッシュする前に一時インスタンスを保存する」という例外をスローしないでください。「null値」を条件付きで設定する場合は、1を実行します。repocall get / findを使用して値をフェッチして設定します。2。次に、フェッチされた値の条件を確認し、それに応じてnullに設定します。以下のコードを貼り付けてテストします。動作していることがわかりました

//トランザクション開始

   オプション<Customer>customerObject= customerRepository.findByCustomerId(customer.getCustomerId())

   if(customerObject.isPresent())yourEnclosingEntityObject.setCustomer(customerObject)}

   else {yourEnclosingEntityObject.setCustomer(null)}

   yourEnclosingEntityObjectRepository.save(yourEnclosingEntityObject)

//トランザクション終了
于 2018-12-09T12:34:20.417 に答える