请在继续说“查询查询中的提取类型”之前阅读。那不是我想要的。
我正在寻找一种方法来急切加载一个完整的对象图(对象+所有子对象及其所有子对象等)。
我不想要枚举要加载的所有属性。直到运行时我才知道它们。
N + 1个查询不是问题。但是在这个神奇的操作结束时,我不希望在我的图表中留下单个代理或惰性集合。
应该可以编写一些反射和递归查看所有属性的代码。但是收藏会使这种尴尬和复杂。
有些人推荐Dozer用于此类事情,但这似乎有点过分,所以我想将其作为最后的手段保存。
答案 0 :(得分:0)
一个简单的解决方案是为所有集合(1:N和N:M)和关联(1:1)指定lazy="false"
。
这会将整个图表加载到每个事务的内存中。因此,要使其正常工作,您最多只能进行一次交易,否则会严重影响性能。
虽然这可以做你想要的,但成本可能太高了。请注意,您可以使用“获取配置文件”在运行时选择不同的策略,但是Hibernate总是会在您请求对象时为您提供一个副本,因此每次都必须复制图形。
对我来说,这听起来像Hibernate只是完成任务的错误工具。使用Hibernate映射实体很舒服,但代价是Hibernate会泄漏到您的模型和业务代码中。如果Hibernate施加的限制不适合您的账单,那么您应该查看其他地方。
也许你可以使用Record
类型而不是完全充实的Java bean。如果是,那么您可以查看jOOQ或frameworks that implement the "active record" pattern。
如果您需要bean并且您不限于某种类型的数据库,请尝试使用db4o等OO数据库。
最后,为什么要使用SQL呢?如果您总是需要整个对象图,为什么不简单地将其序列化为文件并在启动时加载它?或者使用memory-resident database。
答案 1 :(得分:0)
我曾经需要类似的东西,我不得不使用Reflection来解决它。在我的情况下,我使用hql来检索记录。此外,这是我为急切加载定义为延迟加载的记录创建的方法,因此您可能希望调整第一个方法,以便不查找FetchType.LAZY属性并始终以其方式获取它。
我构建的方法之一将“准备”延迟抓取。基本上有两种方法:在@ManyToOne的hql上使用“left join fetch”,在@OneToMany和@ManyToMany上使用hibernate.initialize()。
因此,第一个方法返回一个字符串,其中包含hql所需的“left john fetch”es,并且还构建了一个nToMany字段列表,这些字段必须在执行查询后由Hibernate.initialize()调用。 / p>
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();
}
}
}
我知道这并不完全符合您的预期,但如果您找不到所需的解决方案,它可能会帮助您