hibernate игнорирует fetch = "join" в коллекции при навигации по дереву объектов с помощью итератора - PullRequest
2 голосов
/ 21 сентября 2009

У меня есть форум с 1..n членами, каждый из которых имеет 1..n статей, поэтому это мое отображение:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
      "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping auto-import="true">
   <class name="Forum" table="forum">
      <id name="id">
         <generator class="identity" />
      </id>
      <property name="name" />
      <set name="members" table="members" inverse="true">
         <key column="forum_id" not-null="true" />
         <one-to-many class="Member" />
      </set>
   </class>
   <class name="Article" table="article">
      <id name="id">
         <generator class="identity" />
      </id>
      <property name="title" />

      <many-to-one name="member" column="member_id" class="Member"
         not-null="true">
      </many-to-one>
   </class>
   <class name="Member" table="member">
      <id name="id">
         <generator class="identity" />
      </id>
      <property name="name" />

      <many-to-one name="forum" column="forum_id" class="Forum"
         not-null="true">
      </many-to-one>

      <set name="articles" fetch="join" table="articles"
         inverse="true">
         <key column="member_id" not-null="true" />
         <one-to-many class="Article" />
      </set>
   </class>
</hibernate-mapping>

Теперь у меня есть два теста:

этот сбой с LazyInitializationException:

 public void testFetchJoinByIteratorNavigation ( )
   {
      Forum forum = (Forum) repository.findById(Forum.class, forumId);
      Member member = forum.getMembers().iterator().next();
      assertEquals(member.getName(), "firstMember");
      endTransaction();
      assertEquals(1, member.getArticles().size());
   }

этот преуспевает :

 public void testFetchJoinByGraphNavigation ( )
   {
      Member member = (Member) repository.findById(Member.class, memberId);
      assertEquals(member.getName(), "firstMember");
      endTransaction();
      assertEquals(1, member.getArticles().size());
  }

Единственная разница заключается в способе загрузки элемента.

Ссылка на спящий режим гласит:

"Стратегия выборки, определенная в документе сопоставления, влияет на:

  1. извлечение через get () или load ()
  2. извлечение, которое происходит неявно при навигации по ассоциации
  3. Критерии запросов
  4. HQL-запросы, если используется выборочная выборка "

Последующим тестом является случай 1. (поиск через get () или load ()) Неудачный тест - это случай 2 ИМХО

Почему "forum.getMembers (). Iterator (). Next ()" не загружает все статьи участника?

РЕДАКТИРОВАТЬ 1:

это мой репозиторий:

package hibernate.fetch;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class Repository extends HibernateDaoSupport
{
    public Object findById ( Class clazz, Long objectId )
    {
        return getHibernateTemplate().load(clazz, objectId);
    }

    public void save ( Object object )
    {
        getHibernateTemplate().saveOrUpdate(object);
    }
}

это мой pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>hibernate-fetch</groupId>
    <artifactId>hibernate-fetch</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-eclipse-plugin</artifactId>
                <configuration>
                    <downloadSources>true</downloadSources>
                    <ajdtVersion>1.5</ajdtVersion>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring</artifactId>
            <version>2.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>2.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>3.3.1.GA</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.5.2</version>
        </dependency>
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.8.0.GA</version>
        </dependency>
        <dependency>
            <groupId>postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>8.2-504.jdbc3</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.13</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>2.5.6</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>jmock</groupId>
            <artifactId>jmock</artifactId>
            <version>1.1.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Редактировать 2: это мой тестовый пример:

package hibernate.fetch;

import org.springframework.test.AbstractTransactionalSpringContextTests;

public class ForumTest extends AbstractTransactionalSpringContextTests
{
    private Repository  repository;
    private Long        memberId;
    private Long        forumId;
    private String      name    = "test";

    @Override
    protected String[] getConfigLocations ( )
    {
        return new String[] { "applicationContext.xml" };
    }

    @Override
    protected void onSetUpBeforeTransaction ( ) throws Exception
    {
        System.out.println(">> preparing Test");
        Forum forum = new Forum();
        forum.setName(name);
        repository.save(forum);
        forumId = forum.getId();

        Member member = new Member();
        member.setName(name);
        forum.addMember(member);
        repository.save(member);
        memberId = member.getId();

        Article article = new Article();
        article.setTitle(name);
        member.addArticle(article);

        repository.save(article);

        super.onSetUpBeforeTransaction();
        System.out.println(">> Test prepared");
    }

    public void testFetchJoinByGraphNavigation ( )
    {
        System.out.println(">> testFetchJoinByGraphNavigation");
        Member member = (Member) repository.findById(Member.class, memberId);
        assertEquals(member.getName(), name);
        endTransaction();
        assertEquals(1, member.getArticles().size());
    }

    public void testFetchJoinByIteratorNavigation ( )
    {
        System.out.println(">> testFetchJoinByIterationNavigation");
        Forum forum = (Forum) repository.findById(Forum.class, forumId);
        Member member = forum.getMembers().iterator().next();
        assertEquals(member.getName(), name);
        endTransaction();
        // throws LazyInitializationException because articles were NOT loaded
        assertEquals(1, member.getArticles().size());
    }

    public Repository getRepository ( )
    {
        return repository;
    }

    public void setRepository ( Repository repository )
    {
        this.repository = repository;

}

} * * тысяча пятьдесят-один

Я действительно не понимаю этого!

Ответы [ 3 ]

1 голос
/ 21 сентября 2009

Два случая действительно очень разные.

В неудачном примере вы загружаете сущность Forum, в которой имеется отложенная инициализация коллекции сущностей Member. Когда вы пытаетесь перемещаться по коллекции, происходит сбой, потому что коллекция является отложенной, и вы не загрузили коллекцию до закрытия сеанса.

Рабочий пример, это не «навигация по графику», вы загружаете сущность Member напрямую, поэтому семантика отложенной загрузки не используется.

Документация, на которую вы ссылаетесь, затрагивала различные способы формулировки первого случая, где указание активной загрузки набора членов предотвратит сбой.

0 голосов
/ 28 сентября 2009

Я думаю, что это ошибка документации гибернации.

В справочной документации написано:

"С другой стороны, вы можете использовать соединение извлечение, которое не ленится по своей природе "

В книге JPwH говорится, с. 579

Следовательно, fetch = "join" отключает lazy загрузка.

Это не правда. Когда я изменяю отображение статей на

<set name="articles" fetch="join" lazy="false" table="articles" inverse="true">

оба теста выполняются нормально, но второй тест не запускает соединение при загрузке элемента!

Итак, мой вывод: активная загрузка со стратегией объединений не влияет на инициализацию прокси и не отключает отложенную загрузку. Это отличается от документации по спящему режиму.

0 голосов
/ 22 сентября 2009

Используете ли вы HQL в методе findById (...)? При использовании HQL Hibernate не учитывает ваши настройки выборки / соединения; вам нужно использовать предложение HQL, такое как «выборка левого соединения», чтобы быстро загружать ассоциации. Кроме того, если вы используете Hibernate 2.x, вы не сможете быстро выбрать более одной коллекции в одном запросе. См. FAQ по дополнительным проблемам на веб-сайте гибернации:

https://www.hibernate.org/117.html#A13

...