JPA-запрос с извлечением / соединением, извлекающий только определенные ассоциации - PullRequest
2 голосов
/ 28 февраля 2012

опять мой мозг менее силен, чем логика ....

Мой пример имеет связь один ко многим, когда у Человека много вещей. Элемент имеет свойство Date. Я хочу сделать запрос, в котором извлекается дерево объектов Персоны с определенным связанным набором Предметов, то есть «запрашивать Персоны с Предметами, у которых Дата больше xyz».

Последнее утверждение каждого метода тестирования не выполняется. Но это выражает то, чего я хочу достичь.

Было бы очень приятно помочь мне здесь. Или даже все мое мышление здесь не так? Я предположил, что цель состоит в том, чтобы извлечь объекты, необходимые для единицы работы, из базы данных. Не более или менее. После того, как работа будет завершена, объекты с манипуляциями будут объединены.

Я загрузил проект здесь . Это 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>

@ Амир Пашазаде, 1-й комментатор:

Спасибо за быстрый ответ, Амир. Тестовый случай 'testQueryTheItems' выполняет запрос элементов. После получения списка результатов Предметов я ссылаюсь на связанного с множеством людей человека. Этот человек наоборот ссылается на все связанные предметы. Я хотел бы иметь только один элемент из предыдущего запроса, связанный с человеком. Это касается транзакционных границ? Тип установленных лиц: org.hibernate.collection.internal.PersistentSet. Так это все еще EAGER / LAZY, выбирающий ссылочные позиции? Если бы я сейчас завершил транзакцию, можно ли было бы иметь только один предмет, связывающий одного человека, связывающий один предмет?

1 Ответ

2 голосов
/ 28 февраля 2012

га, Амир был вдохновляющей помощью. Да, он имеет дело с границами 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 и впоследствии закрывается! Это моя настоящая граница передачи, а не фиксация транзакции EntityManager. ... разве я не читал это раньше ... миллион раз ... :-) Ну, тест 'testQueryThePerson' пройдет. Мое предположение было правильным. С другой стороны, тест 'testQueryTheItems' не будет проходить вообще, а будет зависеть от типа выборки ассоциации персонажа Предмета. Установка его FetchType.EAGER извлечет человека и все его предметы. Установив его, FetchType.LAZY будет извлекать человека, но никакого связанного элемента этого человека вообще. Тем не менее, это не то, чего я бы сразу ожидал, потому что я получу Предмет, который объявляет тип ассоциации и выборки относительно Персоны. Персона извлекается в любом случае независимо от того, какой тип извлечения установлен с Элементом. Но тип fetch, похоже, влияет на еще один уровень ассоциаций ...

Рад, что я решил, хотя еще один вопросительный знак поднялся, но я надеюсь, что это поможет кому-то там на этой планете ...

Извините за мой английский, я не являюсь носителем языка ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...