2010-05-12 103 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