我的大脑再一次不如逻辑强大......
我的示例具有一对多关联,其中一个人有许多项目。 项目具有日期属性。我想要执行一个查询,其中检索具有确定的关联项目集的人员的对象树,即“查询具有日期大于 xyz 的项目的人员”。
每个测试方法的最后一个断言失败。但它表达了我想要实现的目标。
非常高兴能在这里帮助我。或者说我的整个想法都是错误的? 我假设目标是检索从数据库中获取工作单元所需的对象。不多也不少。工作完成后,操作的对象将被合并。
我上传了项目here 。 它是Maven2。并且可以通过以下方式运行:mvn test
感谢您为我的大脑提供帮助:-)
这是我的 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”确实查询了项目。收到项目结果列表后,我引用多对一关联人。反之亦然,此人引用所有关联的项目。我只想从前一个查询中获取与该人关联的单个项目。 它涉及交易边界吗? Persons Set 的类型是 org.hibernate.collection.internal.PersistentSet。那么这仍然是 EAGER/LAZY 获取引用的项目吗? 如果我现在结束交易,是否可以只让一件元素关联一个人,关联一件元素?
最佳答案
哈, 阿米尔是鼓舞人心的帮助。是的,它涉及德克萨斯州边界。它进行了以下更改以使其正常工作:
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”根本不会通过,而是取决于项目的人员关联的 fetchtype。 设置 FetchType.EAGER 将获取此人及其所有项目。 设置它 FetchType.LAZY 将获取该人,但根本不获取该人的关联项目。 然而,这并不是我立即期望的,因为我将获得声明与 Person 相关的关联和获取类型的 Item。不管 Item 设置了什么 fetchtype,Person 都会被获取。但 fetchtype 似乎会影响更多一层的关联......
很高兴我解决了这个问题,虽然又出现了一个问号,但我希望这能帮助这个星球上的人......
抱歉我的英语我不是母语者......
关于java - JPA 查询与获取/连接仅检索某些关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9472190/