繁体   English   中英

Hibernate OneToOne 延迟加载和级联

[英]Hibernate OneToOne lazy loading and cascading

这就是我想要做的。

  1. 创建一个与孩子有 OneToOne 关系的父母
  2. 父母必须使用延迟加载来获取孩子
  3. 如果父母被移除,孩子也会被移除
  4. 如果孩子被移除,父母不应该受到影响
  5. 级联更新和删除必须翻译成DDL

class 父级

@OneToOne(mappedBy = "parent", cascade = CascadeType.ALL)
public Child getChild()

class 儿童

@OneToOne(fetch = FetchType.LAZY)
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name="parent_id")
public Parent getParent()

我有第 1、3、4完全工作和第 5 点部分工作,仍然需要解决如何翻译更新部分 indo DDL。

第 2 点是这里的大问题,使用我当前的解决方案,父母不会懒惰地加载孩子。 然而,孩子确实会懒惰地加载父母,但反转注释会打乱级联(第 3、4 和 5 点)。

我现在很困惑,希望我错过了一些明显的东西,所以任何帮助将不胜感激。

编辑: Adeel Ansari 要求的代码

'fetch=FetchType.LAZY' 已添加到 class Parent 中,否则同上。

IParentDAO parentDAO = DAOFactory.getFactory().getParentDAO();

parentDAO.beginTransaction();
//findByPrimaryKey uses 'org.hibernate.Session.get(Class clazz, Serializable id)'
parentDAO.findByPrimaryKey(1l);
parentDAO.commitTransaction();

生成的 hibernate 查询,一个获取父级,一个获取子级:

Hibernate: select parent0_.id as id0_0_ from parents parent0_ where parent0_.id=?
Hibernate: select child0_.id as id1_0_, child0_.parent_id as parent2_1_0_ from childs child0_ where child0_.parent_id=?

这是 findByPrimaryKey 的代码:

public class HibernateParentDAO extends HibernateDAO<Parent, Long> implements IParentDAO {

    public HibernateParentDAO() {
        super(Parent.class);
    }
}

public abstract class HibernateDAO<T, ID extends Serializable> implements IGenericDAO<T, ID> {
    private Class<T> persistentClass;

    public HibernateDAO(Class<T> c) {
        persistentClass = c;
    }

    @SuppressWarnings("unchecked")
    public T findByPrimaryKey(ID id) {
        return (T) HibernateUtil.getSession().get(persistentClass, id);
    }
}

我一直有一个类似的问题。 有几种不同的解决方案,但它们都是解决方法。

简短的回答是: Hibernate 不支持惰性一对一关系。

长答案(解决方法)是:

  1. 将关系声明为在一侧(孩子)是一对一的,在另一侧(父母)是一对多的。 因此parent.getchild()返回一个集合,但它可以使用延迟加载。

  2. 您可以尝试让父项和子项共享主键,但这需要您更改架构。

  3. 您可以尝试在数据库中配置一个反映这种一对一关系的视图。

[这部分不再存在]

在你的Parent中修改这个,如下所示,

@OneToOne(mappedBy = "parent", cascade = CascadeType.ALL, fetch=FetchType.LAZY)
public Child getChild()

应该管用。


[编辑解释为什么它不起作用]

加载 B 后,您可以立即调用 getCee() 来获取 C。 但是看, getCee() 是您的 class 的方法,而 Hibernate 无法控制它。 Hibernate 不知道何时有人会调用 getCee()。 这意味着 Hibernate 必须在从数据库加载 B 时将适当的值放入“cee”属性中。

如果 C 启用了代理,Hibernate 可以放一个 C-proxy object 尚未加载,但有人使用时会加载。 这为一对一提供了延迟加载。

但是现在想象一下您的 B object 可能有也可能没有关联的 C(约束 =“false”)。 当特定 B 没有 C 时 getCee() 应该返回什么? Null。 但请记住,Hibernate 必须在设置 B 的那一刻设置正确的“cee”值(因为它不知道何时有人会调用 getCee())。 代理在这里没有帮助,因为代理本身已经非空 object。

如果您的 B->C 映射是强制性的(约束=true),则 Hibernate 将使用 C 的代理,从而导致延迟初始化。 But if you allow B without C, Hibernate just HAS TO check presence of C at the moment it loads B. But a SELECT to check presence is just inefficient because the same SELECT may not just check presence, but load entire object. 所以延迟加载消失了。

参考: http://community.jboss.org/wiki/Someexplanationsonlazyloadingone-to-one


[已编辑以包含解决方法]

对于非可选的关系,您可以使用optional=false@LazyToOne 不要忘记包含cascade={CascadeType.PERSIST,CascadeType.REMOVE} 因为,对于非可选关系而言,这是显而易见的。 下面是一个例子,

@OneToOne(mappedBy="parent", optional=false, fetch=FetchType.LAZY, cascade={CascadeType.PERSIST,CascadeType.REMOVE})
@LazyToOne(LazyToOneOption.PROXY)
public Child getChild(){...}

这应该对你有用,因为我可以看到你正在使用cascade=CascadeType.ALL ,这意味着不是可选的。 不是吗? 但是对于可选关系,您可能想考虑iliaden 给出的解决方法,这里

您是否尝试过@OneToOne(fetch = FetchType.LAZY, optional=false) 还要检查这个博客和这个线程。

@一对一关系不支持延迟初始化 要获得 object,您不要将 FetchType.LAZY放入子 class 并获取所有子 object。

class Parent

@OneToOne(mappedBy = "parent", cascade = CascadeType.REMOVE)
public Child getChild()

class Child

@OneToOne(cascade = CascadeType.REMOVE)
public Parent getParent()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM