Hibernate OneToOne延迟加载和级联

时间:2011-06-09 08:44:56

标签: java mysql hibernate cascade

这就是我想要做的事情。

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

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

    班级儿童

    @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<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);
        }
    }
    

4 个答案:

答案 0 :(得分:20)

我遇到过类似的问题。有几种不同的解决方案,但所有这些都是解决方法。

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

长答案(解决方法)是:

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

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

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

答案 1 :(得分:11)

[这部分不再存在]

Parent中修改此内容,如下所示

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

应该工作。


[编辑解释为何不起作用]

  

加载B后,您可以打电话   getCee()获得C.但是看,   getCee()是你的类和方法   Hibernate无法控制它。   Hibernate不知道什么时候有人   打算调用getCee()。这意味着   Hibernate必须放一个合适的   价值进入“cee”财产   它从数据库加载B。

     

如果为C,Hibernate启用了代理   可以放一个不是的C代理对象   已加载,但将在何时加载   有人用它。这给了懒惰   加载一对一。

     

但现在想象你的B对象可能或   可能没有相关的C.   (约束= “假”)。什么应该   getCee()在特定B时返回   没有C?空值。但要记住,   Hibernate必须设置正确的值   “cee”在它设定B的那一刻(因为   它不知道什么时候有人打电话   getCee())。代理在这里没有帮助   因为代理本身已经存在   非空对象。

     

如果你的B-> C映射是   强制(约束=真),   Hibernate将使用C代理   导致延迟初始化。但   如果你允许B没有C,Hibernate   只是要检查C的存在   它加载的时刻B.但是一个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, here给出的解决方法。

答案 2 :(得分:7)

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

答案 3 :(得分:-1)

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

class Parent

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

class Child

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