5

在说出“在查询中指定获取类型”的任何内容之前,请继续阅读。那不是我所追求的。

我正在寻找一种方法来急切加载一个完整的对象图(对象+它的所有孩子和他们的所有孩子等等)。

不想枚举所有要加载的属性。直到运行时我才知道它们。

N+1 查询不是问题。但是在这个神奇的操作结束时,我不想在我的图表中留下一个代理或惰性集合。

应该可以编写一些代码来反射和递归地查看所有属性。但是收藏使这变得尴尬和复杂。

有人为这种事情推荐了推土机,但这似乎有点过分,所以我想把它留作最后的手段。

4

2 回答 2

0

一个简单的解决方案是lazy="false"为所有集合(1:N 和 N:M)和关联(1:1)指定。

这将为每个事务将整个图形加载到内存中。因此,要使其正常工作,您最多应该有一个事务,否则会非常非常严重地损害性能。

虽然这会做你想要的,但成本可能太高了。请注意,您可以在运行时使用“获取配置文件”来选择不同的策略,但是当您请求对象时,Hibernate 总是会给您一个副本以供您使用,因此它必须每次都复制图形。

对我来说,这听起来像是 Hibernate 只是完成任务的错误工具。使用 Hibernate 映射实体很舒服,但代价是 Hibernate 泄漏到您的模型和业务代码中。如果 Hibernate 施加的约束不符合您的要求,那么您应该寻找其他地方。

也许您可以使用Record类型而不是完全充实的 Java bean。如果是这样,那么您可以查看实现“活动记录”模式的jOOQ或框架。

如果您需要 bean 并且您不限于某种类型的数据库,请尝试使用 OO 数据库,例如db4o

最后,你为什么要使用 SQL?如果你总是需要整个对象图,为什么不简单地将它序列化为一个文件并在启动时加载它呢?或者使用内存驻留数据库

于 2013-01-07T12:54:33.023 回答
0

我曾经需要类似的东西,我不得不使用反射来解决它。就我而言,我使用 hql 来检索记录。此外,这是我为定义为延迟加载的急切加载记录创建的一种方法,因此您可能希望调整第一种方法以不查找 FetchType.LAZY 属性并始终获取它。

我构建的一种方法将“准备”延迟获取。基本上有两种方法:在@ManyToOne 的hql 上使用“left join fetch”,为@OneToMany 和@ManyToMany 使用hibernate.initialize()。

因此,第一个方法返回一个字符串,其中包含 hql 所需的“left john fetch”es,并且还构建了一个 nToMany 字段列表,在执行查询后必须由 Hibernate.initialize() 调用这些字段。

private String buildLazyFetch(Class<? extends GenericEntity> entityClass, List<String> nToManyFields) {
    String lazyFetches = new String();
    lazyFetches += " fetch all properties ";
    // iterate through all fields looking for lazy loaded relationships
    for (Field f : entityClass.getDeclaredFields()) {
        ManyToOne manyToOne = f.getAnnotation(ManyToOne.class);
        if (manyToOne != null) {
            if (manyToOne.fetch().equals(FetchType.LAZY)) {
                lazyFetches += " left join fetch t." + f.getName() + " ";
            }
        }
        OneToMany oneToMany = f.getAnnotation(OneToMany.class);
        if (oneToMany != null) {
            if (oneToMany.fetch().equals(FetchType.LAZY)) {
                nToManyFields.add(f.getName());
            }
        }
        ManyToMany manyToMany = f.getAnnotation(ManyToMany.class);
        if (manyToMany != null) {
            if (manyToMany.fetch().equals(FetchType.LAZY)) {
                nToManyFields.add(f.getName());
            }
        }
    }
    return lazyFetches;
}

并在执行 hql 后,调用:

private void lazyFetchNToMany (List<String> nToManyFields, GenericEntity entity) {
    for (String field : nToManyFields) {
        try {
            Hibernate.initialize(BeanUtils.getProperty(entity, field));
        } catch (HibernateException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

我了解这与您的预期不完全一样,但如果您找不到所需的解决方案,它可能会帮助您

于 2013-01-07T13:24:56.710 回答