Hibernate OneToOne延迟加载和级联

这就是我想要做的。

  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’已添加到类Parent,否则与上面相同。

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

生成的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=? 

这是findByPrimaryKey的代码:

 public class HibernateParentDAO extends HibernateDAO implements IParentDAO { public HibernateParentDAO() { super(Parent.class); } } public abstract class HibernateDAO implements IGenericDAO { private Class persistentClass; public HibernateDAO(Class 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()是你的类的一个方法,而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(){...} 

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

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

@一对一的关系不支持延迟初始化 。 要获取对象, 不要将FetchType.LAZY放在子类中并获取所有子对象。

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