2010-05-12 86 views
1

我在我的數據庫中存儲了一些blob,所以我有一個Document表和一個DocumentContent表。文檔包含文件名,描述等,並具有DocumentContent屬性。防止nHibernate中的延遲加載

我有一個Silverlight客戶端,所以我不想加載並將DocumentContent發送到客戶端,除非我明確要求它,但是我在執行此操作時遇到問題。

我已閱讀Davy Brion的博客文章。我已經嘗試將lazy = false放置在我的配置中,並刪除虛擬訪問修飾符,但迄今爲止還沒有運氣。

每次我做一個Session.Get(id)時,DocumentContent都是通過外部聯接來檢索的。我只希望這個屬性在我明確地加入到這張表中並且要求時填充。

任何幫助表示讚賞。

我NHibernate的映射如下:

<?xml version="1.0" encoding="utf-8" ?> 

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
        assembly="Jrm.Model" 
        namespace="Jrm.Model"> 
    <class name="JrmDocument" lazy="false"> 
    <id name="JrmDocumentID"> 
     <generator class="native" /> 
    </id> 

    <property name="FileName"/> 
    <property name="Description"/> 
    <many-to-one name="DocumentContent" class="JrmDocumentContent" unique="true" column="JrmDocumentContentID" lazy="false"/> 
    </class> 


    <class name="JrmDocumentContent" lazy="false"> 
    <id name="JrmDocumentContentID"> 
     <generator class="native" /> 
    </id> 

    <property name="Content" type="BinaryBlob" lazy="false"> 
     <column name="FileBytes" sql-type="varbinary(max)"/> 
    </property> 

    </class> 
</hibernate-mapping> 

和我的課是:

[DataContract] 
    public class JrmDocument : ModelBase 
    { 
     private int jrmDocumentID; 
     private JrmDocumentContent documentContent; 
     private long maxFileSize; 
     private string fileName; 
     private string description; 

     public JrmDocument() 
     { 
     } 

     public JrmDocument(string fileName, long maxFileSize) 
     { 
      DocumentContent = new JrmDocumentContent(File.ReadAllBytes(fileName)); 
      FileName = new FileInfo(fileName).Name; 
     } 

     [DataMember] 
     public virtual int JrmDocumentID 
     { 
      get { return jrmDocumentID; } 
      set 
      { 
       jrmDocumentID = value; 
       OnPropertyChanged("JrmDocumentID"); 
      } 
     }    

     [DataMember] 
     public JrmDocumentContent DocumentContent 
     { 
      get { return documentContent; } 
      set 
      { 
       documentContent = value; 
       OnPropertyChanged("DocumentContent"); 
      } 
     }   

     [DataMember] 
     public virtual long MaxFileSize 
     { 
      get { return maxFileSize; } 
      set 
      { 
       maxFileSize = value; 
       OnPropertyChanged("MaxFileSize"); 
      } 
     } 


     [DataMember] 
     public virtual string FileName 
     { 
      get { return fileName; } 
      set 
      { 
       fileName = value; 
       OnPropertyChanged("FileName"); 
      } 
     } 

     [DataMember] 
     public virtual string Description 
     { 
      get { return description; } 
      set 
      { 
       description = value; 
       OnPropertyChanged("Description"); 
      } 
     } 
    } 



    [DataContract] 
    public class JrmDocumentContent : ModelBase 
    { 
     private int jrmDocumentContentID; 
     private byte[] content; 

     public JrmDocumentContent() 
     { 
     } 
     public JrmDocumentContent(byte[] bytes) 
     { 
      Content = bytes; 
     } 

     [DataMember] 
     public int JrmDocumentContentID 
     { 
      get { return jrmDocumentContentID; } 
      set 
      { 
       jrmDocumentContentID = value; 
       OnPropertyChanged("JrmDocumentContentID"); 
      } 
     } 

     [DataMember] 
     public byte[] Content 
     { 
      get { return content; } 
      set 
      { 
       content = value; 
       OnPropertyChanged("Content"); 
      } 
     } 
    } 
+1

聽起來像延遲加載正是你想要的 – UpTheCreek 2010-05-12 05:49:14

+0

這不是我想要的。考慮UI體驗。我將獲得用戶可能選擇0+的文檔列表。我不希望在我明確要求它的情況下才能檢索DocumentContent - 如果用戶甚至不打算使用它們,這將是一個巨大的性能拖動來加載所有DocumentContents。所以當用戶點擊文檔時,我將有第二次服務調用來實際檢索文檔,包括DocumentContent – 2010-05-12 06:16:17

+0

我不想延遲加載的原因是,我首先想要將文檔列表發送到客戶端,用戶將選擇這些文檔之一,然後我將檢索包含DocumentContent的文檔以供他們保存。 因爲我使用的是Silverlight,所以當Document被序列化時,DocumentContent會被觸及,然後延遲加載。如果我關閉延遲加載,那麼它會被熱切地提取。我只是不想讓它完全恢復 – 2010-05-12 06:22:12

回答

0

我有在我的關係進行管理(逆=真),也是一個問題與我的會話實例化,因爲它正在被注入英寸。使用它與自定義DataContractSurrogate,防止一些懶惰加載問題現在的作品。

感謝

var proxy = obj as INHibernateProxy; 
if (proxy != null) 
{ 
    var initializer = proxy.HibernateLazyInitializer; 
    if (initializer.IsUninitialized) 
    { 
     return Activator.CreateInstance(obj.GetType().BaseType); } 
    else 
    { 
     return initializer.GetImplementation(); 
    } 
} 
2

如果你想推遲裝載,然後設置爲lazy =地圖中的 「真」。

+0

我試過lazy =「true」和lazy =「false」。既沒有達到預期的效果。我不希望DocumentContent被加載 - 懶惰或以其他方式加載,除非我通過選擇條件明確地加載。 我以前使用LLBL Gen,並且在適配器模型中,除非通過預取明確請求,否則不會加載關係。我想在nHibernate中做類似的事情 – 2010-05-12 06:19:48

2

您應該爲您的服務使用DTO,並使用lazy = true離開,而不是序列化您的域模型。這是一個巨大的性能增益。

+0

我不想現在將我的應用程序更改爲DTO。我的很多課程都非常輕量級,並且在大多數情況下都可以很好地工作。 – 2010-05-13 01:26:15

+1

然後使用DTO作爲不完美的人。 – 2010-05-24 02:36:27

0

你描述的場景正是延遲加載是專爲。

想要顯示包含摘要信息的列表,並在需要時加載較重的東西。這是懶加載。這是「懶惰」,因爲它避免了在絕對需要的情況下做額外的工作。

你想要的是讓JrmDocumentContent懶洋洋地加載,而且你正在順利地加載。爲了得到這個,你必須刪除lazy = false。 lazy = true是nhibernate中的默認值,但您可以將lazy = true設置爲true。不過你必須恢復虛擬機。

懶洋洋地加載blob或者其他任何屬性,我想通過在屬性定義中設置lazy = true來支持nhibernate的最新版本。

將大量內容分隔到單獨的類/表中使用的方法是以前懶惰地加載blob的唯一方法。我不知道你使用的是什麼版本的nhibernate,但你採用的策略是正確的。你應該接受延遲加載。您還需要在JrmDocumentContent類的Content屬性上移除lazy = false。除此之外,我沒有看到其他理由爲什麼它沒有工作。

0

我已經有這個問題。

這是我做了什麼:

  1. 創建自己的自定義代理服務器(使用城堡DynamicProxy,但你可以嘗試其他人)返回在所有未初始化的屬性和集合null,並返回一個副本每個初始化集合。我用這樣的代理將每個根對象結果包裝在我的服務中。將此代理作爲我的服務的返回值傳遞 - 幾乎可行,但我無法讓我的代理自己正確序列化。這就是爲什麼我嘗試方法2:

  2. (可怕)深入克隆我的所有實體到新的對象,跳過未初始化的屬性和集合。這工作,但很糟糕。

  3. 目前我正在嘗試使用DataContractSurrogate來解決1.中的問題,或者完全替換代理的使用。我目前試圖解決的問題是,您無法「過濾」對象屬性 - 您不能從GetObjectToSerialize返回null - 如果被序列化的對象是未初始化的NHibernate代理或集合,這正是我想返回的內容。

我會在進展時更新此答案。目前,我正在使用解決方案2作爲臨時解決方法。我會分享代碼,但目前情況很糟糕(因爲我不打算深度克隆成爲解決方案)。

+0

這解決了使用DataContractSurrogate的問題。我可以檢查是否有代理並覆蓋該屬性並將其設置爲新的默認實例。即var proxy = obj作爲INHibernateProxy; if(proxy!= null){var initializer = proxy.HibernateLazyInitializer; if(initializer.IsUninitialized){return Activator.CreateInstance(obj.GetType()。BaseType); } else {return initializer.GetImplementation(); }} – 2011-04-01 04:26:41

+0

我已經考慮過這個解決方案,但是然後我們序列化空實例而不是空值。這不僅是通信中的浪費,還意味着客戶端無法判斷它收到的對象是否真的沒有從數據庫中獲取,或者只是將其所有字段都設置爲數據庫中的默認值(空實例)。 – sinelaw 2011-04-03 07:18:00

+0

順便說一句,不是運行深層克隆,而是將自定義代理直接傳遞給序列化程序,並與DataContractSurrogate結合使用,該代碼只將自定義代理的合約類型替換爲基類(代理類)類型。包含在其中的NHibernate代理會被我的自定義代理自動屏蔽掉。仍然不是一個完美的解決方案,但至少由此產生的溝通是我想要的,並且不需要深度克隆。 – sinelaw 2011-04-03 07:21:37