在说出“在查询中指定获取类型”的任何内容之前,请继续阅读。那不是我所追求的。
我正在寻找一种方法来急切加载一个完整的对象图(对象+它的所有孩子和他们的所有孩子等等)。
我不想枚举所有要加载的属性。直到运行时我才知道它们。
N+1 查询不是问题。但是在这个神奇的操作结束时,我不想在我的图表中留下一个代理或惰性集合。
应该可以编写一些代码来反射和递归地查看所有属性。但是收藏使这变得尴尬和复杂。
有人为这种事情推荐了推土机,但这似乎有点过分,所以我想把它留作最后的手段。
在说出“在查询中指定获取类型”的任何内容之前,请继续阅读。那不是我所追求的。
我正在寻找一种方法来急切加载一个完整的对象图(对象+它的所有孩子和他们的所有孩子等等)。
我不想枚举所有要加载的属性。直到运行时我才知道它们。
N+1 查询不是问题。但是在这个神奇的操作结束时,我不想在我的图表中留下一个代理或惰性集合。
应该可以编写一些代码来反射和递归地查看所有属性。但是收藏使这变得尴尬和复杂。
有人为这种事情推荐了推土机,但这似乎有点过分,所以我想把它留作最后的手段。
一个简单的解决方案是lazy="false"
为所有集合(1:N 和 N:M)和关联(1:1)指定。
这将为每个事务将整个图形加载到内存中。因此,要使其正常工作,您最多应该有一个事务,否则会非常非常严重地损害性能。
虽然这会做你想要的,但成本可能太高了。请注意,您可以在运行时使用“获取配置文件”来选择不同的策略,但是当您请求对象时,Hibernate 总是会给您一个副本以供您使用,因此它必须每次都复制图形。
对我来说,这听起来像是 Hibernate 只是完成任务的错误工具。使用 Hibernate 映射实体很舒服,但代价是 Hibernate 泄漏到您的模型和业务代码中。如果 Hibernate 施加的约束不符合您的要求,那么您应该寻找其他地方。
也许您可以使用Record
类型而不是完全充实的 Java bean。如果是这样,那么您可以查看实现“活动记录”模式的jOOQ或框架。
如果您需要 bean 并且您不限于某种类型的数据库,请尝试使用 OO 数据库,例如db4o。
最后,你为什么要使用 SQL?如果你总是需要整个对象图,为什么不简单地将它序列化为一个文件并在启动时加载它呢?或者使用内存驻留数据库。
我曾经需要类似的东西,我不得不使用反射来解决它。就我而言,我使用 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();
}
}
}
我了解这与您的预期不完全一样,但如果您找不到所需的解决方案,它可能会帮助您