簡體   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