Hibernate OneToOne延迟加载和级联

Hol*_*olm 7 java mysql hibernate cascade

这就是我想要做的.

  1. 创建与子项具有OneToOne关系的父级
  2. 父级必须使用延迟加载来获取子级
  3. 如果父母被移除,那么孩子也是如此
  4. 如果孩子被移除,父母不应受到影响
  5. 级联更新和删除必须转换为DDL

班级家长

@OneToOne(mappedBy = "parent", cascade = CascadeType.ALL)
public Child getChild()
Run Code Online (Sandbox Code Playgroud)

班级孩子

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

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

第2点是这里的一个大问题,我目前的解决方案是父母不会懒惰加载孩子.然而,孩子懒得加载父母,但是反转注释会使级联变得混乱(第3,4和5点).

我现在很困惑,希望我错过了一些明显的东西,所以任何帮助都会非常感激.

编辑: Adeel Ansari要求的代码

'fetch = FetchType.LAZY'已添加到类Parent,否则与上面相同.

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

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

生成的hibernate查询,一个获取Parent,一个获取Child:

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=?
Run Code Online (Sandbox Code Playgroud)

这是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);
    }
}
Run Code Online (Sandbox Code Playgroud)

ili*_*den 20

我一直有类似的问题.有几种不同的解决方案,但所有这些都是解决方法.

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

答案很长(解决方法)是:

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

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

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


Ade*_*ari 11

[此部分不再存在]

Parent下面修改它,

@OneToOne(mappedBy = "parent", cascade = CascadeType.ALL, fetch=FetchType.LAZY)
public Child getChild()
Run Code Online (Sandbox Code Playgroud)

应该管用.


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

在加载B之后,你可以调用getCee()来获得C.但是看看,getCee()是你的类的一个方法,而Hibernate无法控制它.Hibernate不知道有人打算调用getCee().这意味着Hibernate必须在从数据库加载B时将适当的值放入"cee"属性.

如果为C启用了代理,Hibernate可以放置一个尚未加载的C代理对象,但是当有人使用它时将加载它.这为一对一提供了延迟加载.

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

如果你的B-> C映射是强制性的(约束=真),Hibernate将使用C代理导致延迟初始化.但是如果你允许B没有C,那么Hibernate只是在它加载B时检查C的存在.但是检查存在的SELECT效率很低,因为相同的SELECT可能不仅仅检查存在,而是加载整个对象.懒惰的装载消失了.

参考: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(){...}
Run Code Online (Sandbox Code Playgroud)

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


aba*_*ogh 7

你试过@OneToOne(fetch = FetchType.LAZY, optional=false)吗?另请查看博客和主题.