2012-02-27 15 views
2

我的大腦比邏輯強大少....JPA查詢與取/聯接再次檢索只有某些協會

我的例子有一個一對多的關聯,當一個人有很多項目。 一個物品有一個日期屬性。我想做一個查詢,其中具有確定的相關聯的一組項目的人的對象樹被檢索,即'查詢具有大於xyz的日期的項目的人員'。

每個測試方法的最後一個斷言失敗。但它表達了我想達到的目標。

會很高興幫助我在這裏。或者,甚至我的整個想法在這裏都不對? 我假定目標是檢索從數據庫中提取的工作單元所需的對象。不多或少。工作完成後,操作對象將被合併。

我上傳了項目here。 這是Maven2。並且可以運行:MVN測試

感謝您的幫助wringng M個大腦:-)

這裏是我的JUnit測試:

package de.greyshine.jpaSelectJoinDate; 

import java.util.*; 
import javax.persistence.*; 
import junit.framework.Assert; 
import org.junit.*; 

public class Tester { 

    EntityManager em; 

    static final Date DATE1 = createDate(2012, Calendar.JANUARY, 1); 
    static final Date DATE2 = createDate(2012, Calendar.MARCH, 1); 

    static Date createDate(int inYear, int inMonth, int inDayOfMonth) { 
     final Calendar theCalendar = Calendar.getInstance(); 
     theCalendar.set(Calendar.YEAR, inYear); 
     theCalendar.set(Calendar.MONTH, inMonth); 
     theCalendar.set(Calendar.DAY_OF_MONTH, inDayOfMonth); 
     return theCalendar.getTime(); 
    } 

    @Before 
    public void _junitBeforeClass() { 
     final EntityManagerFactory emf = Persistence.createEntityManagerFactory("testPu"); ; 
     em = emf.createEntityManager(); 
     em.setFlushMode(FlushModeType.COMMIT); 

     final Person p = new Person(); 
     final Item i1 = new Item(); 
     i1.date = DATE1; 
     i1.person = p; 
     final Item i2 = new Item(); 
     i2.date = DATE2; 
     i2.person = p; 
     p.items.add(i1); 
     p.items.add(i2); 

     em.getTransaction().begin(); 
     em.persist(i1); 
     em.persist(i2); 
     em.persist(p); 
     em.getTransaction().commit(); 
    } 

    @Test 
    public void testQueryTheItems() { 

     em.getTransaction().begin(); 
     final Query theQuery = em.createQuery("FROM Tester$Item i WHERE i.date > :inDate"); 

     theQuery.setParameter("inDate" , DATE1, TemporalType.TIMESTAMP); 
     @SuppressWarnings("unchecked") 
     final List<Item> theResults = (List<Item>)theQuery.getResultList(); 
     em.getTransaction().commit(); 
     Assert.assertEquals(1, theResults.size()); 
     Item theItem = theResults.iterator().next(); 
     Assert.assertEquals(theItem.date.getTime(), DATE2.getTime()); 
     Assert.assertNotNull(theItem.person); 
     Assert.assertEquals(1, theItem.person.items.size()); 
    } 

    @Test 
    public void testQueryThePerson() { 

     em.getTransaction().begin(); 
     final Query theQuery = em.createQuery("FROM Tester$Person p JOIN FETCH p.items i WHERE i.date > :inDate"); 

     theQuery.setParameter("inDate" , DATE1, TemporalType.TIMESTAMP); 
     @SuppressWarnings("unchecked") 
     final List<Person> theResults = (List<Person>)theQuery.getResultList(); 
     em.getTransaction().commit(); 
     Assert.assertEquals(1, theResults.size()); 
     Person thePerson = theResults.iterator().next(); 
     System.out.println(thePerson); 
     Assert.assertEquals(1, thePerson.items.size()); 
    } 

    @Entity 
    @Table(name="persons") 
    public static class Person { 

     @Id 
     @GeneratedValue 
     public Long id; 

     @OneToMany 
     final Set<Item> items = new HashSet<Item>(); 

     @Override 
     public String toString() { 
      return "Person [items="+ items +"]"; 
     } 
    } 

    @Entity 
    @Table(name="items") 
    public static class Item { 

     @Id 
     @GeneratedValue 
     public Long id; 

     @Column 
     @Temporal(TemporalType.TIMESTAMP) 
     Date date; 

     @ManyToOne 
     Person person; 

     @Override 
     public String toString() { 
      return "Item [id="+id+"; date="+ date +"; person.id="+ (person==null?null:person.id) +"]"; 
     } 
    } 
} 

爲了完整起見,這裏是我的persistence.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="1.0" 
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
         http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> 
    <persistence-unit name="applicationManagedPersistenceUnit" transaction-type="RESOURCE_LOCAL"> 
     <provider>org.hibernate.ejb.HibernatePersistence</provider> 
     <class>de.greyshine.jpaauction.entity.Buyer</class> 
     <class>de.greyshine.jpaauction.entity.Seller</class> 
     <class>de.greyshine.jpaauction.entity.Item</class> 
     <class>de.greyshine.jpaauction.entity.Bid</class> 
     <properties> 
      <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:unit-testing-jpa" /> 
      <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" /> 
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> 
      <property name="hibernate.show_sql" value="true" /> 
      <property name="hibernate.hbm2ddl.auto" value="create" /> 
      <property name="hibernate.connection.username" value="sa" /> 
      <property name="hibernate.connection.password" value="" /> 
     </properties> 
    </persistence-unit> 
</persistence> 

@Amir Pashazadeh,第一個評論者:

感謝您的快速銷售代表埃米爾。測試用例'testQueryTheItems'確實查詢項目。在收到物品的結果清單後,我會參考多對一的相關人員。這個人反之亦然引用所有相關的項目。我想從與該人關聯的前一個查詢中獲得單個項目。 它處理事務性邊界嗎? Person的類型是org.hibernate.collection.internal.PersistentSet。那麼這仍然是EAGER/LAZY獲取引用的項目嗎? 如果我現在要結束交易,是否有可能只有一個項目與一個人相關聯,從而將一個項目關聯起來?

+1

嘗試查詢項目,然後導航到人員,這將幫助您只有滿足條件的項目才能在查詢結果中 – 2012-02-27 21:13:07

回答

2

ha, 埃米爾是鼓舞人心的幫助。是的,它處理W/TX邊界。它做了以下修改以使其正常工作:

public class Tester { 

    static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("testPu"); ; 
    EntityManager em; 

    ...  

    @BeforeClass 
    public static void _junitBeforeClass() { 
     final EntityManager em = emf.createEntityManager(); 
     em.setFlushMode(FlushModeType.COMMIT); 

     final Person p = new Person(); 
     final Item i1 = new Item(); 
     i1.date = DATE1; 
     i1.person = p; 
     final Item i2 = new Item(); 
     i2.date = DATE2; 
     i2.person = p; 
     p.items.add(i1); 
     p.items.add(i2); 

     em.getTransaction().begin(); 
     em.persist(i1); 
     em.persist(i2); 
     em.persist(p); 
     em.getTransaction().commit(); 

     em.close(); 
    } 

    @Before 
    public void _junitBefore() { 
     em = emf.createEntityManager(); 
     em.setFlushMode(FlushModeType.COMMIT); 
    } 

    @After 
    public void _junitAfter() { 
     em.close(); 
    } 
... 

EntityManager負責我的工作單元。當一個工作單元啓動時,EntityManager由EntityManagerFactory創建並在之後關閉!這是我真正的TX邊界,而不是EntityManager事務的提交。 ...我沒有讀過......百萬次...... :-) 那麼,測試'testQueryThePerson'會通過。我的猜測是對的。 另一方面,測試'testQueryTheItems'根本不會通過,而是依賴於Item的人員關聯的獲取類型。 設置它FetchType.EAGER將獲取人員和所有人的物品。 設置它FetchType.LAZY將獲取該人,但根本沒有該人的相關項目。然而,這不是我所期望的,因爲我會得到一個Item,它聲明瞭關於Person的關聯和獲取類型。總之,無論什麼取件類型都與物品一起設置,人物都會被抓取。但fetchtype似乎影響更多關聯的一級...

高興的是,我雖然解決了另一個問號惜售毛刺我希望這會幫助別人那裏在這個星球上......

對不起,我的英語我不是母語的人......