簡體   English   中英

休眠:初始化與取消代理

[英]Hibernate: initialize vs unproxy

我在使用 ManyToMany 時遇到問題

@ManyToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
@JoinTable(
    name = "PORTFOLIO_USER_PERMS",
    joinColumns = { @JoinColumn(name = "USERNAME") },
    inverseJoinColumns = { @JoinColumn(name = "PORTFOLIO_ID"), }
)
private List<Portfolio> sharedPortfolios = new ArrayList<>();

我有一個場景,其中一個 sharedPortfolios 一個元素是代理,另一個元素有一個代理屬性(由於一對一關系,actulay 是同一個對象)。 此列表通常返回到 Controller 方法,然后將其轉換為相應的 DTO。 正如您可能懷疑的那樣,具有代理對象的單個屬性會導致LazyInitializationException

在此處輸入圖片說明

這意味着在服務中,我需要遍歷列表中的每個元素,在將其傳遞給控制器​​之前,使用 Hibernate Utility: Hibernate.unproxy(...)查找可能是代理和取消代理的任何屬性。

我的問題:

1) Hibernate.initializeHibernate.unproxy 有什么區別?

初始化代理對象並不能解決問題。

2) 為什么其中一個元素是代理,而其他元素不是?

3)有什么比手動遍歷此列表和所有屬性並搜索代理對象更好的方法?

非常感謝。

此致。

要回答您的第一個問題,您可以查看這兩種方法的實現:

    /**
     * Unproxies a {@link HibernateProxy}. If the proxy is uninitialized, it automatically triggers an initialization.
     * In case the supplied object is null or not a proxy, the object will be returned as-is.
     *
     * @param proxy the {@link HibernateProxy} to be unproxied
     * @return the proxy's underlying implementation object, or the supplied object otherwise
     */
    public static Object unproxy(Object proxy) {
        if ( proxy instanceof HibernateProxy ) {
            HibernateProxy hibernateProxy = (HibernateProxy) proxy;
            LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer();
            return initializer.getImplementation();
        }
        else {
            return proxy;
        }
    }

    /**
     * Force initialization of a proxy or persistent collection.
     * <p/>
     * Note: This only ensures initialization of a proxy object or collection;
     * it is not guaranteed that the elements INSIDE the collection will be initialized/materialized.
     *
     * @param proxy a persistable object, proxy, persistent collection or <tt>null</tt>
     * @throws HibernateException if we can't initialize the proxy at this time, eg. the <tt>Session</tt> was closed
     */
    public static void initialize(Object proxy) throws HibernateException {
        if ( proxy == null ) {
            return;
        }

        if ( proxy instanceof HibernateProxy ) {
            ( (HibernateProxy) proxy ).getHibernateLazyInitializer().initialize();
        }
        else if ( proxy instanceof PersistentCollection ) {
            ( (PersistentCollection) proxy ).forceInitialization();
        }
        else if ( proxy instanceof PersistentAttributeInterceptable ) {
            final PersistentAttributeInterceptable interceptable = (PersistentAttributeInterceptable) proxy;
            final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor();
            if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) {
                ( (EnhancementAsProxyLazinessInterceptor) interceptor ).forceInitialize( proxy, null );
            }
        }
    }

對於實體代理( HibernateProxy )的實例,這兩種方法本質上是相同的,唯一的區別是unproxy返回未經代理的實體。 從我到目前為止的測試來看,無論您使用返回值還是原始引用,都沒有區別。

initialize也適用於持久集合( PersistentCollection )。 當您需要初始化 ToMany-Relation 時,就像在您的問題中一樣,您將需要使用此方法。

初始化代理對象並不能解決問題。

您需要初始化集合sharedPortfolios ,而不僅僅是包含集合的對象:

Hibernate.initialize(entity.sharedPortfolios)

或者,您可能希望JOIN FETCH查詢中的關系或使用實體圖以避免事后初始化並避免額外的查詢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM