2017-09-30 11 views
0

JPAプロバイダとしてHibernate 5.2.11を使用しています。私は多対1の関係を持つフィールドとして別の注釈付きクラス(Customer)を持つ注釈付きクラス(PurchaseOrder)を持っています。従来のコードでは異なるデータベースにCustomerテーブルとPOテーブルがあるため、Customerインスタンスを返すためにPurchaseOrderでEntityManagerのgetReference()を呼び出しています。私は、Hibernateを使用する自家製のクラスを通してこれらにアクセスします(詳細は後述)。 これは、次の例外が生じている:getReference()を使用しているときにHibernate JPAがLazyInitialization例外をスローするのはなぜですか?

org.hibernate.LazyInitializationException:プロキシ初期化できませんでした - 私はHibernateは、JPAおよびJava EEドキュメントを読んされてきた無セッション

を、しかし、されていません私が間違っていることを困惑させることができます。私は、HibernateがJPAの機能を有効にするためにシーンの背後にあるセッションを使用していることを知っていますが、私が.getCustomer()にアクセスするとき、私は新しいEntityManagerを作成しています。

私は理解の重要な部分を欠いていることは明白ですが、私はそれが何であるか分かりません。誰でも私を啓発することはできますか?ここで

は文字列、整数、ブール値とLocalDatesで構成発注の重要な部分である(すなわち:彼らはすべての@Basicフィールドです):

@Entity 
@Table(name = "PurchaseOrder") 
public class PurchaseOrder extends BaseEntity { // BaseEntity is a @mappedSuperclass containing the primary key info only. 
... 
    private Integer customerID; 
    private Customer customer; 
... 
    @Column(name = "customerID") 
    public Integer getCustomerID() { 
     return customerID; 
    } 

    public void setCustomerID(Integer customerID) { 
     this.customerID = customerID; 
    } 

    @Transient 
    public Customer getCustomer() { 
     LOG.info("Getting customer #{}", customerID); 
     if (customerID != 0 && (customer == null || !customerID.equals(customer.getId()))) { 
      customer = VdtsSysDB.getDB().get(Customer.class, customerID); 
     } 
     return customer; 
    } 

    public void setCustomer(Customer customer) { 
     this.customer = customer; 
     this.customerID = customer.getId(); 
    } 
... 

のみ含まれるクラスとして、および顧客をそして、これが唯一の@Basicフィールドから構成顧客、次のとおりです。

@Entity 
@Table(name = "Customers") 
public class Customer extends BaseEntity{ 
    private String custNo; 
    private String businessName; 
    private String contact; 
... 
    @Column(name = "custNo") 
    public String getCustNo() { 
     return custNo; 
    } 

    public void setCustNo(String custNo) { 
     this.custNo = custNo; 
    } 

    @Column(name = "Name") 
    public String getBusinessName() { 
     return businessName; 
    } 

    public void setBusinessName(String businessName) { 
     this.businessName = businessName; 
    } 

    @Column(name = "Contact") 
    public String getContact() { 
     return contact; 
    } 

    public void setContact(String contact) { 
     this.contact = contact; 
    } 
    ... 

これは私のHibernateのユーティリティクラスです:

public class VdtsSysDB { 
    private EntityManagerFactory entityManagerFactory; 
    private static VdtsSysDB vdtsSysDB; 

    public static VdtsSysDB getDB() { 
     if (vdtsSysDB == null) { 
      vdtsSysDB = new VdtsSysDB(); 
     } 
     return vdtsSysDB; 
    } 

    private VdtsSysDB() { 
     if (entityManagerFactory == null) 
      entityManagerFactory = Persistence.createEntityManagerFactory("VDTS_SYSDB"); 
    } 

    public EntityManager getEntityManager() { 
     return entityManagerFactory.createEntityManager(); 
    } 

    public void closeEntityManager(EntityManager entityManager) { 
     try { 
      entityManager.close(); 
     } catch (Exception e) { 
      // Exception logging. 
     } 
    } 
... 
    /** 
    * Issues an HQL Query and returns the results as a list. 
    * 
    * @param queryString - An HQL query. 
    * @return A list of items representing the returned dataset. 
    */ 
    public <T extends BaseEntity> List<T> query(String queryString) { 
     List<T> results = null; 
     LOG.info("Query: {}", queryString); 
     EntityManager entityManager = null; 
     try { 
      entityManager = getEntityManager(); 
      results = entityManager.createQuery(queryString).getResultList(); 
      entityManager.close(); 
      LOG.info("Returned {} results.", results.size()); 
     } catch (Exception e) { 
      if (entityManager != null && entityManager.isOpen()) entityManager.close(); 
      LOG.error("Unable to complete query {}.", queryString, e); 
     } 
     return results; 
    } 

    /** 
    * Get an object from the database by specifying its class and its ID. 
    * @param aClass the class type to be returned. 
    * @param id the primary key to the item to be returned. 
    * @param <T> the class type to be returned. 
    * @return A single instance of the specified item of this class. 
    */ 
    public <T extends BaseEntity> T get(Class aClass, Integer id) { 
     LOG.info("Get #: {}, {}", id, aClass.getName()); 
     T result = null; 
     EntityManager entityManager = null; 
     try { 
      entityManager = getEntityManager(); 
      Object object = entityManager.getReference(aClass, id); 
      result = (T) object; 
     } catch (Exception e) { 
      LOG.error("Could not get {}", id, e); 
     } finally { 
      closeEntityManager(entityManager); 
     } 
     return result; 
    } 
} 

例外をスローするコードは、JavaFX 8アプリケーションコントローラの一部です。クラスloadでinitialize()が呼び出され、接続されたGUIが表示されるたびにrefreshPane()が呼び出されます。例外は、Customer.getBusinessName()の呼び出しでスローされます。

@FXML 
private TableView<PurchaseOrder> poTable; 
@FXML 
private TableColumn<PurchaseOrder, String> poNoCol; 
@FXML 
private TableColumn<PurchaseOrder, String> customerNameCol; 
@FXML 
private TableColumn<PurchaseOrder, LocalDate> orderDateCol; 

@Override 
protected void initialize() { 
    super.initialize(); 
    poTable.getSelectionModel().selectedItemProperty().addListener(
      (observable, oldValue, newValue) -> { 
       if (newValue != null) selectItem(); 
      }); 
    poNoCol.setCellValueFactory(new PropertyValueFactory<>("purchaseOrderNo")); 
    customerNameCol.setCellValueFactory(param -> { 
     PurchaseOrder po = param.getValue(); 
     Customer customer = po.getCustomer(); 
     String name = customer.getBusinessName(); /****** This is the line that throws the exception ******/ 
     StringProperty observableString = new SimpleStringProperty(name); 
     return observableString; 
      }); 
    orderDateCol.setCellValueFactory(new PropertyValueFactory<>("orderDate"));  
... 
} 

@Override 
protected void refreshPane() { 
    List<Customer> oList = VdtsSysDB.getDB().query("from Customer"); 
    customerCombo.setItems(FXCollections.observableList(oList)); 
    changeTable(); 
    clearWidgets(); 
    enableWidgets(false); 
} 

private void changeTable() { 
    poTable.getSelectionModel().clearSelection(); 
    List<PurchaseOrder> oList = VdtsSysDB.getDB() 
      .query("from PurchaseOrder where closed = " + (openRadio.isSelected() ? "0" : "1")); 
    poTable.setItems(FXCollections.observableList(oList)); 
} 
... 

例外の完全なスタックトレース:

30-09-17 19:42:05.137 ERROR java.lang.Throwable - Exception in thread "JavaFX Application Thread" org.hibernate.LazyInitializationException: could not initialize proxy - no Session 
30-09-17 19:42:05.137 ERROR java.lang.Throwable - at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:146) 
30-09-17 19:42:05.138 ERROR java.lang.Throwable - at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:259) 
30-09-17 19:42:05.139 ERROR java.lang.Throwable - at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:73) 
30-09-17 19:42:05.139 ERROR java.lang.Throwable - at ca.vdts.buchanan.model.Customer_$$_jvst799_9.getBusinessName(Customer_$$_jvst799_9.java) 
30-09-17 19:42:05.139 ERROR java.lang.Throwable - at ca.vdts.buchanan.endtally.controllers.POController.lambda$initialize$1(POController.java:103) 
30-09-17 19:42:05.140 ERROR java.lang.Throwable - at javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:578) 
30-09-17 19:42:05.140 ERROR java.lang.Throwable - at javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:563) 
30-09-17 19:42:05.140 ERROR java.lang.Throwable - at javafx.scene.control.TableCell.updateItem(TableCell.java:644) 
30-09-17 19:42:05.141 ERROR java.lang.Throwable - at javafx.scene.control.TableCell.indexChanged(TableCell.java:468) 
30-09-17 19:42:05.141 ERROR java.lang.Throwable - at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:116) 
30-09-17 19:42:05.141 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.TableRowSkinBase.updateCells(TableRowSkinBase.java:533) 
30-09-17 19:42:05.141 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.TableRowSkinBase.init(TableRowSkinBase.java:147) 
30-09-17 19:42:05.142 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.TableRowSkin.<init>(TableRowSkin.java:64) 
30-09-17 19:42:05.142 ERROR java.lang.Throwable - at javafx.scene.control.TableRow.createDefaultSkin(TableRow.java:212) 
30-09-17 19:42:05.142 ERROR java.lang.Throwable - at javafx.scene.control.Control.impl_processCSS(Control.java:872) 
30-09-17 19:42:05.142 ERROR java.lang.Throwable - at javafx.scene.Node.processCSS(Node.java:9058) 
30-09-17 19:42:05.143 ERROR java.lang.Throwable - at javafx.scene.Node.applyCss(Node.java:9155) 
30-09-17 19:42:05.143 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1964) 
30-09-17 19:42:05.143 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1797) 
30-09-17 19:42:05.143 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.VirtualFlow.getCellLength(VirtualFlow.java:1879) 
30-09-17 19:42:05.144 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.VirtualFlow.computeViewportOffset(VirtualFlow.java:2528) 
30-09-17 19:42:05.144 ERROR java.lang.Throwable - at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1189) 
30-09-17 19:42:05.144 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1087) 
30-09-17 19:42:05.144 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093) 
30-09-17 19:42:05.145 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093) 
30-09-17 19:42:05.145 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093) 
30-09-17 19:42:05.145 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093) 
30-09-17 19:42:05.145 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093) 
30-09-17 19:42:05.146 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093) 
30-09-17 19:42:05.146 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093) 
30-09-17 19:42:05.146 ERROR java.lang.Throwable - at javafx.scene.Parent.layout(Parent.java:1093) 
30-09-17 19:42:05.147 ERROR java.lang.Throwable - at javafx.scene.Scene.doLayoutPass(Scene.java:552) 
30-09-17 19:42:05.147 ERROR java.lang.Throwable - at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2397) 
30-09-17 19:42:05.147 ERROR java.lang.Throwable - at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:355) 
30-09-17 19:42:05.147 ERROR java.lang.Throwable - at java.security.AccessController.doPrivileged(Native Method) 
30-09-17 19:42:05.148 ERROR java.lang.Throwable - at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:354) 
30-09-17 19:42:05.148 ERROR java.lang.Throwable - at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:381) 
30-09-17 19:42:05.148 ERROR java.lang.Throwable - at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:510) 
30-09-17 19:42:05.148 ERROR java.lang.Throwable - at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490) 
30-09-17 19:42:05.149 ERROR java.lang.Throwable - at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$404(QuantumToolkit.java:319) 
30-09-17 19:42:05.149 ERROR java.lang.Throwable - at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95) 
30-09-17 19:42:05.150 ERROR java.lang.Throwable - at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) 
30-09-17 19:42:05.150 ERROR java.lang.Throwable - at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) 
30-09-17 19:42:05.150 ERROR java.lang.Throwable - at java.lang.Thread.run(Thread.java:745) 

答えて

1

オイ。あなたが質問を投稿した後で答えを見つけ出すだけの理由は何ですか?

この例外は、私がEntityManager.getReference()を使用したためにスローされています。 Java EEのJPAのJavadocから

が状態遅延フェッチかもしれインスタンスを、取得します。要求された インスタンスがデータベースに存在しない場合は、インスタンス状態に初めてアクセスするときに、EntityNotFoundException がスローされます。 (getReferenceが呼び出されたときに、 プロバイダ実行時に をスローすることが許可されています)。 エンティティマネージャが開いている間にアプリケーションによってアクセスされた場合を除き、アプリケーションはデタッチ時にインスタンス状態を利用できません。

getReferenceが遅れて取得したCustomerのフィールドにアクセスしようとしました。これらのフィールドは、EntityManagerを閉じる前に初期化されていないため、それらを参照しようとするとLazyInitialization例外がスローされます。

解決策は明らかです。getReferenceは使用しないでください。代わりにEntityManager.find()を使用してください。

関連する問題