2017-12-27 9 views
1

更新がNullPointerExceptionが冬眠withiと春ブーツ

私は@ sainrの答えConverting Hibernate proxy to real entity objectは、問題を解決していることに注意したいと思いますFetchType.LAZYで発生します。しかし、このシーンの背後にある問題は、finalという修飾語を持つSiteEntityです。setControllerEntitygetControllerEntityです。これは私の質問では持ちませんでした。そして私は謝罪します。

final修飾子を削除します。その後、Hibernateはプロキシオブジェクトを正常に初期化できます。

説明は、別のanswerのStack Overflowで見つけることができます。


私は、デバイスの実体を発見した後

@Entity 
@Table(name = "controller") 
public class ControllerEntity { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(nullable = false, updatable = false) 
    private long id; 
} 

@Entity 
@Table(name = "site") 
public class SiteEntity { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(nullable = false) 
    private long id; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "controller_id", nullable = false) 
    private ControllerEntity controllerEntity; 
} 

@Entity 
@Table(name = "device") 
public class DeviceEntity { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(nullable = false) 
    private long id; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "site_id", nullable = true) 
    private SiteEntity siteEntity; 
} 

を次のように3つのエンティティを持って、私はそれから直接controllerEntityを取得しよう。

final DeviceEntity deviceEntity1 = deviceRepository.findOne(1L); 
System.out.println(deviceEntity1.getSiteEntity().getControllerEntity().getId()); 

しかし、それはsiteEntitynullcontrollerEntityによって引き起こされるjava.lang.NullPointerException結果。

また、siteRepositoyを使用してsiteEntityをもう一度フェッチしようとしても、それのcontrollerEntityはまだnullです。

DeviceEntityとSiteEntityの両方からfetch = FetchType.LAZYを削除した後、NPEはもう発生しません。

しかし、それは奇妙に思えますし、意味がありません。 hibernateが正しい値を取得することを期待しながら、FetchType.LAZYを使用できますか?

ありがとうございました。

答えて

2

FetchType.LAZYで宣言されたフィールドにアクセスするために、HibernateはCGLIBでプロキシを構築します。したがって、そのようなフィールドのゲッター(あなたの場合はgetSiteEntity()またはgetControllerEntity())を呼び出しているときは、フィールド値に直接アクセスしていません。代わりに、呼び出しはHibernateのプロキシオブジェクトに渡されます。次に、Hibernateはデータストアから実際の値をロードしようとします。これを行うには、DBにアクセスするためにアクティブなHibernateセッションが必要です。おそらく、あなたのケースでは、Hibernateセッションはすでに閉じられており、そのような遅延ロードは失敗し、事実上フィールドの値はnullになります。(Converting Hibernate proxy to real entity objectを確認してください)実際のオブジェクトにプロキシオブジェクトを変換

  1. 使用FetchType.EAGER保持対象物DeviceEntity
  2. と一緒にすべてのフィールド値をロードすることとアクセス:

    は基本的に2つのこれを解決する方法がありますそれは普通の方法でです

本当にあなたの場合に怠惰な負荷が必要かどうか、それについて考えてみてください。必要に応じてロードするために、子フィールドに重いオブジェクトをたくさん格納していない場合は、おそらくFetchType.EAGERに切り替えるのが最も簡単な方法です。

希望に役立ちます。

+1

ありがとう。それは実際に重いオブジェクトを含んでいません。私は代わりにEAGERに切り替えます。しかし、重いオブジェクトやManyToMany、OneToManyマッピングなど、FetchType.LAZYが必要な場合は、休止セッションを閉じたり、「プロキシオブジェクトを実際のオブジェクトに変換する」ことを避けるために、そこに行きますか?ありがとう – Chiu

+1

@Chiu 'TransactionTemplate'内で使うことができます(ホルダーオブジェクトをロードし、遅延した子を' @ Transactional'としてアクセスするメソッドをマークしてください) – sainr

+1

「Hibernateプロキシを実体に変換するオブジェクト "は問題を解決します。しかし、シーンの背後にある問題は、私の 'SiteEntity'が' setControllerEntity'と 'getControllerEntity'の' final'修飾子を持つことです。 'final'修飾子を削除します。その後、Hibernateはプロキシオブジェクトをちょうど良いものに初期化できます。 – Chiu

2

Hibernateはプリミティブ型で動作しないことがあります。ラッパークラスの代わりに、プリミティブ型を使用することをお勧めし

private long id 

休止の主キーについては

private Long id 

に置き換えるようにしてください。

+0

ありがとうございます!私は最近の研究でどのように冬眠しているプリミティブ型のヌル値を処理する方法を見つける – Chiu