2

我有一个论坛,有 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;

}

}

我真的不明白!

4

3 回答 3

1

这两种情况真的很不一样。

在失败的示例中,您正在加载 Forum 实体,该实体具有惰性初始化的 Member 实体集合。当您尝试浏览该集合时,它会失败,因为该集合是一个惰性集合,并且您在会话关闭之前没有加载该集合。

工作示例,这不是“图形导航”,您直接加载成员实体,因此不涉及延迟加载语义。

您所指的文档涉及第一种情况的不同表述方式,其中在成员集上指定急切加载将防止失败。

于 2009-09-21T17:36:53.120 回答
0

您是否在 findById(...) 方法中使用 HQL?使用 HQL 时,Hibernate 不尊重您的 fetch/join 设置;您需要使用 HQL 子句,例如“left join fetch”,以使关联被急切地加载。此外,如果您是 Hibernate 2.x,您将无法在单个查询中急切地获取多个集合。请参阅 hibernate 网站上的高级问题常见问题解答:

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

于 2009-09-21T22:57:24.337 回答
-1

我认为这是一个休眠文档错误。

在参考文档中它说:

“另一方面,您可以使用连接提取,这本质上是非懒惰的”

在 JPwH 书中它说,p。579

因此, fetch="join" 禁用延迟加载。

这不是真的。当我将我的文章映射更改为

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

两个测试都运行良好,但第二个测试在加载成员时没有运行连接!

所以我的结论是:使用 joins 策略进行 Eager fetching 不会影响代理初始化,也不会禁用延迟加载。这与休眠文档相反。

于 2009-09-28T12:10:41.380 回答