3

给定以下映射

<class name="com.domain.Season" table="cm.pub.jsn_mstr">
    <id name="seasonCode" column="season_code" length="1"/>
    <property name="name" type="string" column="name" length="20"/>
    <set name="promotions" lazy="false">
        <key column="season_code"/>
        <one-to-many class="com.domain.Promotion" not-found="ignore"/>
    </set>
</class>

如何包含或排除负载promotionslazy="true"尽管我正在使用 Jackson 来序列化会话关闭后的结果,但我可以使用它。

public Collection<Season> getSeasons(boolean withPromotions) {
    final Session session = sessionFactory.getCurrentSession();
    try {
        session.beginTransaction();
        return (List<Season>) session.createQuery("from Season s").list();
    } finally {
        session.getTransaction().commit();
    }
}

更新:使用延迟加载的问题。

上面的getSeasons方法用于将检索季节的 MVC 控制器,然后使用 jackson 将它们序列化为 JSON(使用 Spring/MVC 的视图解析器),因此我自己实际上并不访问对象,因此任何尝试延迟加载集合结果在异常中(因为杰克逊将在所有集合属性上调用迭代器)。

这是一个显示将引发异常的示例:

public Collection<Season> getSeasons(boolean withPromotions) {
    final Session session = sessionFactory.getCurrentSession();
    final List<Season> r;
    try {
        session.beginTransaction();
        r = (List<Season>) session.createQuery(
                withPromotions
                ? "from Season s join fetch s.promotions"
                : "from Season s"
                ).list();
    } finally {
        session.getTransaction().commit();
    }
    try {
        for (Season s : r) {
            for (Promotion p : s.getPromotions()) {
                // Exception thrown here as we attempted to get an iterator.
                LOG.debug("Promotion: " + p.getName());
            }
        }
    } catch (Exception ex) {
        LOG.error("Couldn't get promotions", ex);
    }
    return r;
}

当然,这次映射需要有,lazy="true"否则它总是会急切地阅读集合。

<class name="com.domain.Season" table="cm.pub.jsn_mstr">
    <id name="seasonCode" column="jsn_seas" length="1"/>
    <set name="promotions" lazy="true">
        <key column="jpr_seas"/>
        <one-to-many class="com.domain.Promotion" not-found="ignore"/>
    </set>
</class>

promotions字段的数据类型是Collection<Promotion>

4

5 回答 5

3

试试这个:

session.createQuery("from Season s join fetch s.promotions").list();

来自休眠参考:“获取”连接允许使用单个选择来初始化值的关联或集合以及它们的父对象。

于 2012-02-23T04:59:58.000 回答
2

您可以使用Hibernate.initialize()从代理初始化集合。在您的示例中,添加以下代码。

public Collection<Season> getSeasons(boolean withPromotions) {
    final Session session = sessionFactory.getCurrentSession();
    try {
        session.beginTransaction();
        List<Season> list = session.createQuery("from Season s").list();
        for(Season s : list){
            if(condition){
               Hibernate.initialize(s.getPromotions());
            }
        }
        return list;


    } finally {
        session.getTransaction().commit();
    }
}

从 API 文档中,这将,

静态方法 Hibernate.initialize() 和 Hibernate.isInitialized() 为应用程序提供了一种使用延迟初始化的集合或代理的便捷方式。Hibernate.initialize(cat) 将强制初始化代理 cat,只要它的 Session 仍然打开。Hibernate.initialize(cat.getKittens()) 对小猫的收集有类似的效果。

在此处阅读 API或在此处阅读示例。

于 2012-02-23T02:48:52.990 回答
0

我发现我能做到这一点的唯一方法是不映射集合,而是发送两个查询,然后自己添加到集合中。

这使我可以更好地控制关联并提高性能,因为我只发送两个查询而不是 1+n(其中 n 是从第一个查询中检索到的行)。

于 2012-02-25T07:08:42.180 回答
0

本质上,您的问题是杰克逊——阅读 bean 中的所有内容。不是休眠。

任何一个:

1)正确控制杰克逊,传输你真正需要的数据——并避免你不希望它“拉上”的东西。

2)使用 Spring 的 'OpenSessionInViewFilter'或类似的将 Session 绑定到线程本地,并使其保持打开状态,直到视图运行 - 使 Jackson 仍能在视图渲染阶段“拉上”并加载集合。

3) 或者,将两个不同的类(一个完整的细节,一个轻量级)映射到同一个表,然后检索您实际需要的那个。

SeasonLite 可能是Season 的祖先(完整细节),但请注意,您没有使用Hibernate 映射继承——您正在映射同一个表的两个单独视图。

PS:像 'getSomeData(boolean retrieveThisData)' 这样的方法似乎是一种常见的反模式。我以前见过很多次。

于 2012-09-29T01:57:02.210 回答
0

对不起,这是一个很晚的答案,但我只是在寻找其他东西时才发现你的问题。

正如一些答案中已经说明的那样,问题在于 Hibernate 使用“占位符”PersistentCollection来进行延迟加载集合。要阻止 Hibernate 在访问时尝试填写集合,您可以在查询返回的每个实体中null输出实际Promotions列表。Season在代码中,是这样的:

if (!withPromotions) {
    for (Season s : r) {
        s.setPromotions(null);
    }
}

将 设置Promotions为 null 将清除对 Hibernate 集合对象的引用。您应该能够在会话之外执行此操作。

我们所做的是在我们的实体上为我们的每个集合创建方法,类似于:

public boolean isPromotionsLoaded() {
    if (((promotions instanceof org.hibernate.collection.PersistentCollection)
            && !((org.hibernate.collection.PersistentCollection) promotions).wasInitialized())
            || (getPromotions() == null)) {
        return false;
    } else {
        return true;
    }
}

然后我们可以使用这些方法来确定我们是否可以安全地访问该集合。

无论如何,希望这对某人有所帮助。

于 2014-12-04T20:39:45.207 回答