2011-07-29 58 views
2

我遇到問題。我正在學習JPA。我在單元測試中使用嵌入式OpenEJB容器,但只能工作在@OneToMany(fetch=EAGER)。否則,集合總是空的。我還沒有發現,懶惰策略是如何工作的,容器如何填充數據以及在哪些情況下觸發容器的加載操作?什麼是懶惰的策略,它是如何工作的?

我已經讀過,這個動作會在getter被調用時觸發。但是當我有代碼:

@OneToMany(fetch = LAZY, mappedBy="someField") 
private Set<AnotherEntities> entities = new Set<AnotherEntities>(); 
... 
public Set<AnotherEntities> getEntities() { 
    return entities; 
} 

我總是變空。我的事情,懶惰的戰略不能用嵌入式容器進行測試。這個問題也可能是雙向關係。

在JPA測試中是否有其他人類似的expiriences?

附件

真正的測試用例設置:

@RunWith(UnitilsJUnit4TestClassRunner.class) 
@DataSet("dataSource.xml") 
public class UnitilsCheck extends UnitilsJUnit4 { 
    private Persister prs; 

    public UnitilsCheck() { 
     Throwable err = null; 
     try { 
      Class.forName("org.hsqldb.jdbcDriver").newInstance(); 
      Properties props = new Properties(); 
      props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory"); 
      props.put("ds", "new://Resource?type=DataSource"); 
      props.put("ds.JdbcDriver", "org.hsqldb.jdbcDriver"); 
      props.put("ds.JdbcUrl", "jdbc:hsqldb:mem:PhoneBookDB"); 
      props.put("ds.UserName", "sa"); 
      props.put("ds.Password", ""); 
      props.put("ds.JtaManaged", "true"); 
      Context context = new InitialContext(props); 
      prs = (Persister) context.lookup("PersisterImplRemote"); 
     } 
     catch (Throwable e) { 
      e.printStackTrace(); 
      err = e; 
     } 
     TestCase.assertNull(err); 
    } 

    @Test 
    public void obtainNickNamesLazily() { 
     TestCase.assertNotNull(prs); 
     PersistableObject po = prs.findByPrimaryKey("Ferenc"); 
     TestCase.assertNotNull(po); 
     Collection<NickNames> nicks = po.getNickNames(); 
     TestCase.assertNotNull(nicks); 
     TestCase.assertEquals("[Nick name: Kutyafája, belongs to Ferenc]", nicks.toString()); 
    } 
} 

的豆Presister是豆調解訪問實體Bean。類的關鍵代碼如下:

@PersistenceUnit(unitName="PhonePU") 
protected EntityManagerFactory emf; 

public PhoneBook findByPrimaryKey(String name) { 
    EntityManager em = emf.createEntityManager(); 

    PhoneBook phonebook = (PhoneBook)em.find(PhoneBook.class, name); 
    em.close(); 

    return phonebook; 
} 

實體PhoneBook是電話簿(也人)一行。一個人可以有零個或更多的暱稱。隨着EAGER策略的運作。隨着LAZY收集是無效的。可能是問題在於分離物體。 (請參閱OpenEJB - JPA Concepts,部分緩存和分離。)但是在手冊中,有時候(更多時候很多時候)這個集合是空的,但不是空的。

+0

你可以用設置,實際測試和拆卸顯示測試嗎? –

+0

在這裏要清楚...你使用的OpenJPA是OpenEJB使用的JPA實現。據我所知,OpenEJB不是JPA實現。 – DataNucleus

+0

是的,我是。我的測試使用嵌入式OpenEJB,OpenEJB使用OpenJPA。 –

回答

2

的問題是一個實體的生命週期。 (Geronimo使用OpenJPA,所以不要看OpenJPA教程,部分爲Entity Lifecycle Management。)應用程序使用容器管理的事務。豆Persiser上的每個方法調用都在自己的轉換中運行。持久性上下文取決於事務。實體在事務結束時與其上下文斷開連接,因此在方法結束時斷開連接。我嘗試獲取實體並在第二行中使用相同的方法獲取暱稱的集合,並且它工作正常。因此,問題得到了確認:我無法從數據存儲中另外獲取任何實體數據,而無需將實體重新附加到某個持久性上下文。該實體通過EntityManager.merge()方法重新附加。

該代碼需要更多的正確。因爲實體無法獲得EntityManager參考並重新附加自身,所以返回暱稱名稱的方法必須移至Persister類。 (註釋Heureka標誌着臨界線重新連接的實體。)

public Collection<NickNames> getNickNamesFor(PhoneBook pb) { 
    //emf is an EntityManagerFactory reference 
    EntityManager em = emf.createEntityManager(); 
    PhoneBook pb = em.merge(pb); //Heureka! 
    Collection<NickNames> nicks = pb.getNickNames(); 
    em.close(); 
    return nicks; 
} 

收集,然後以這種方式獲得:

//I have a PhoneBook instance pb 
//pb.getNickNames() returns null only 
//I have a Persister instance pe 
nicks = pe.getNickNames(pb); 

這就是全部。

你可以看看我的第二個問題,關於我在這個論壇上詢問的這個話題。這是問題OpenJPA - lazy fetching does not work

0

我怎麼會寫代碼

@Entity 
public class MyEntity { 

    @OneToMany(fetch = LAZY, mappedBy="someField") 
    private Set<AnotherEntities> entities; 

    // Constructor for JPA 
    // Fields aren't initalized here so that each em.load 
    // won't create unnecessary objects 
    private MyEntity() {} 

    // Factory method for the rest 
    // Have field initialization with default values here 
    public static MyEntity create() { 
    MyEntity e = new MyEntity(); 
    e.entities = new Set<AnotherEntities>(); 
    return e; 
    } 

    public Set<AnotherEntities> getEntities() { 
    return entities; 
    } 

} 

理念沒有2:

我只是認爲在急切和懶惰取操作的順序可能會有所不同,即EAGER取可

  1. 聲明字段entities
  2. 取價值entities(我假設null
  3. entities設定值new Set<T>()

entitiesnew Set<T>() LAZY可能

  1. 申報現場`實體
  2. 設定值
  3. 提取值爲entities(我假設爲null)'

必須爲此找到引用。

理念沒有1:(不正確的答案)

如果你註釋什麼,吸氣,而不是場?這應該指示JPA使用getter和setter來代替字段訪問。

在Java持久性API,一個實體可以有基於場或 基於財產訪問。在基於字段的訪問中,持久性提供者 直接通過其實例 變量來訪問實體的狀態。在基於性質的訪問中,持久性提供者使用 JavaBeans風格的獲取/設置訪問器方法來訪問實體的 持久性屬性。

The Java Persistence API - A Simpler Programming Model for Entity Persistence

+0

當我將字段的註解移動到getter時,出現'ArgumentException':_It嘗試同時使用字段和屬性訪問。只有一種訪問方法是允許的。但是,如何禁用字段訪問的答案正在風中吹噓:o | –

+1

在谷歌上花了一段時間後,我發現,在外地和財產訪問之間一定不能有區別。推薦的方法是使用字段訪問,也不註釋getter,但是註釋字段。問題在於OpenEJB中的mabye。 –

+0

我試過了。它不使用'create()'方法。 –