我在hibernate中编写一个函数,以递归方式递归初始化对象的所有属性,从而加载整个对象图。
我有两个复杂的场景,我需要使用这个
1)自组合对象,如类别和子类别......
@Entity
public class Category {
@Column(nullable = false, length = 50)
@NotNull
@Size(max = 50, message = "{50}")
protected String name;
@ManyToOne(targetEntity = Category.class, fetch = FetchType.LAZY, optional = true)
private Category parentCategory;
}
2)复杂的对象图,在使用之前有很多要初始化的对象。
问题是我不能使用渴望获取,因为我只在选择性情况下需要这个整个对象图,我想要通用代码,所以不需要为对象编写HQL查询。
我为此写了部分代码,
public void recursiveInitliaze(Object obj) throws Exception {
if(!Hibernate.isInitialized(obj))
Hibernate.initialize(obj);
PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
for (PropertyDescriptor propertyDescriptor : properties) {
Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
if (origProp != null) {
this.recursiveInitliaze(origProp);
}
if (origProp instanceof Collection && origProp != null) {
for (Object item : (Collection) origProp) {
this.recursiveInitliaze(item);
}
}
}
}
但它有一个问题,由于双向关系,它结束于方法调用的stackoverflow。那么如何检测双向关系还是有更好的方法来实现它?
我认为获取配置文件也可以提供帮助但仍然希望尝试实现此功能,因为在项目的当前阶段配置获取配置文件很困难。
答案 0 :(得分:8)
完整代码:
public <T> T recursiveInitliaze(T obj) {
Set<Object> dejaVu = Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>());
try {
recursiveInitliaze(obj, dejaVu);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
ReflectionUtils.handleReflectionException(e);
}
return obj;
}
private void recursiveInitliaze(Object obj, Set<Object> dejaVu) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
if (dejaVu.contains(this)) {
return;
} else {
dejaVu.add(this);
if (!Hibernate.isInitialized(obj)) {
Hibernate.initialize(obj);
}
PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj);
for (PropertyDescriptor propertyDescriptor : properties) {
Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());
if (origProp != null) {
this.recursiveInitliaze(origProp, dejaVu);
}
if (origProp instanceof Collection && origProp != null) {
for (Object item : (Collection<?>) origProp) {
this.recursiveInitliaze(item, dejaVu);
}
}
}
}
}
ReflectionUtils代码:
/**
* Handle the given reflection exception. Should only be called if no
* checked exception is expected to be thrown by the target method.
* <p>Throws the underlying RuntimeException or Error in case of an
* InvocationTargetException with such a root cause. Throws an
* IllegalStateException with an appropriate message else.
* @param ex the reflection exception to handle
*/
public static void handleReflectionException(Exception ex) {
if (ex instanceof NoSuchMethodException) {
throw new IllegalStateException("Method not found: " + ex.getMessage());
}
if (ex instanceof IllegalAccessException) {
throw new IllegalStateException("Could not access method: " + ex.getMessage());
}
if (ex instanceof InvocationTargetException) {
handleInvocationTargetException((InvocationTargetException) ex);
}
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
throw new UndeclaredThrowableException(ex);
}
答案 1 :(得分:7)
您可以在对象上使用Hibernate.initialize()
来初始化它。我不确定这是否会级联。否则,您可以检查instanceof HibernateProxy
,它会为您提供isInitialised属性。
更新:由于初始化不会级联,因此您需要像往常一样遍历树。使用Hashset跟踪已处理的对象。