java - JPA 查询与获取/连接仅检索某些关联

标签 java jpa fetch

我的大脑再一次不如逻辑强大......

我的示例具有一对多关联,其中一个人有许多项目。 项目具有日期属性。我想要执行一个查询,其中检索具有确定的关联项目集的人员的对象树,即“查询具有日期大于 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/

相关文章:

java - 标签重新排列

Hibernate无法添加外键约束

java - 添加到集合中时,类不会保留新的关联对象

javascript - React 新手 - 使用 Fetch

java - SNMP4J : What does "Inconsistent naming used" error mean?

java - 如何在 spring-batch 中计算 Tasket 中的项目?

java - 具有oneToMany关系的Spring boot rest api post方法

PHP PDO - 显示特定的行和列

javascript - 当其中一个获取延迟响应时,如何在 Redux 中进行多次获取操作?

java - Eclipse 剪切/复制/粘贴不起作用