Hibernate OneToOne 延迟加载和级联

发布于 2024-11-14 18:53:46 字数 2030 浏览 4 评论 0原文

这就是我正在尝试做的事情。

  1. 创建与子级具有 OneToOne 关系的
  2. 父级 父级必须使用延迟加载来获取子级
  3. 如果父级被删除,子级也会被删除
  4. 如果子级被删除,父级不应受到影响
  5. 级联更新和删除必须进行转换进入 DDL

class Parent

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

class Child

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

我已经完全实现了第 1、3、4 点第 5 点部分实现了正在工作,还需要解决如何翻译更新部分印度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);
    }
}

Here's what I'm trying to do.

  1. Create a parent with a OneToOne relation to a child
  2. The parent has to fetch the children using lazy loading
  3. If parent is removed, so is the child
  4. If the child is removed, the parent should not be affected
  5. The cascade update and delete has to be translated into DDL

class Parent

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

class Child

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

I've got point 1, 3, 4 fully working and Point 5 partially working, still need to solve how to translate the update part indo DDL.

Point 2 is the big issue here, with my current solution the parent does not load the child lazily. The child however does load the parent lazily, but inverting the annotations would mess upp the cascading (points 3, 4 and 5).

I'm very confused right now, hoping I've missed something obvious, so any help would be greatly appreciated.

EDIT: Code requested by Adeel Ansari

'fetch=FetchType.LAZY' has been added to class Parent, otherwise the same as above.

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

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

The resulting hibernate queries, one fetching Parent and one fetching 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=?

Here's the code for 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);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

咋地 2024-11-21 18:53:46

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

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

长答案(解决方法)是:

  1. 将关系声明为一对一的关系(子级)和一对多的关系(父级)。因此,parent.getchild() 返回一个集合,但它将能够使用延迟加载。

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

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

I've been having a similar issue. There are a few different solutions, but all of them are workarounds.

The short answer is: Hibernate does NOT support lazy one-to-one relationships.

The long answer (workaround) is:

  1. Declare the relationship to be one-to-one on one side (child), and one-to-many on the other side (parent). Thus a parent.getchild() returns a set, yet it will be able to use lazy loading.

  2. You can try to have the parent and the children to share the primary key, but this would require you to alter the schema.

  3. You can try to configure a view in your database reflecting this one-to-one relationship.

摇划花蜜的午后 2024-11-21 18:53:46

[这部分不再成立]

在您的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
(约束=“假”)。应该做什么
当特定 B 执行时 getCee() 返回
没有C?无效的。但请记住,
Hibernate 必须设置正确的值
“cee”此时设置 B(因为
它不知道什么时候有人会打电话来
getCee())。代理在这里没有帮助
因为代理本身已经
非空对象。

如果您的 B->C 映射是
强制(约束= true),
Hibernate将为C使用代理
导致延迟初始化。但
如果你允许 B 而没有 C,Hibernate
只需检查 C 是否存在
加载 B 的那一刻。但是 SELECT 到
检查存在效率很低
因为同一个 SELECT 可能不只是
检查存在,但加载整个
目的。所以延迟加载消失了。

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


[编辑以包含解决方法]

您可以使用 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,此处给出的解决方法。

[This part doesn't hold anymore]

Modify this in your Parent like below,

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

Should work.


[Edited to explain why it will not work]

Right after loading B, you may call
getCee() to obtain C. But look,
getCee() is a method of YOUR class and
Hibernate has no control over it.
Hibernate does not know when someone
is going to call getCee(). That means
Hibernate must put an appropriate
value into "cee" property at the
moment it loads B from database.

If proxy is enabled for C, Hibernate
can put a C-proxy object which is not
loaded yet, but will be loaded when
someone uses it. This gives lazy
loading for one-to-one.

But now imagine your B object may or
may not have associated C
(constrained="false"). What should
getCee() return when specific B does
not have C? Null. But remember,
Hibernate must set correct value of
"cee" at the moment it set B (because
it does no know when someone will call
getCee()). Proxy does not help here
because proxy itself in already
non-null object.

If your B->C mapping is
mandatory (constrained=true),
Hibernate will use proxy for C
resulting in lazy initialization. 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. So lazy loading goes away.

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


[Edited to include a workaround]

You can use optional=false and @LazyToOne for the relationship that is not optional. Don't forget to include cascade={CascadeType.PERSIST,CascadeType.REMOVE}. Since, it is obvious for a not-optional relationship. Below is an example,

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

This should work for you, as I can see you are using cascade=CascadeType.ALL, which means not-optional. Isn't it? But for optional relationship, you might like to consider workaround given by iliaden, here.

飞烟轻若梦 2024-11-21 18:53:46

您是否尝试过@OneToOne(fetch = FetchType.LAZY,可选= false)?
另请查看博客和此主题

Have you tried @OneToOne(fetch = FetchType.LAZY, optional=false)?
Also check this blog and this thread.

记忆で 2024-11-21 18:53:46

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

class Parent

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

class Child

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

@One-to-one relationship not support lazy initialization.
To get object you don't put FetchType.LAZY in child class and obtain all child object.

class Parent

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

class Child

@OneToOne(cascade = CascadeType.REMOVE)
public Parent getParent()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文