防止nHibernate中的延迟加载

时间:2010-05-12 05:32:59

标签: silverlight nhibernate nhibernate-mapping lazy-loading

我在我的数据库中存储了一些blob,所以我有一个Document表和一个DocumentContent表。文档包含文件名,描述等,并具有DocumentContent属性。

我有一个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");
            }
        }
    }

6 个答案:

答案 0 :(得分:2)

如果您想延迟加载,请在地图中设置lazy =“true”。

答案 1 :(得分:2)

您应该将DTO用于您的服务,并将所有内容保留为lazy = true,而不是序列化您的域模型。这是一个很大的性能提升。

答案 2 :(得分:1)

第一个经验法则:

  • 不分发您的域对象

http://martinfowler.com/bliki/FirstLaw.html

答案 3 :(得分:0)

我的关系被管理的地方(inverse = true)以及我正在注入的会话实例化时遇到了问题。将其与自定义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(); 
    } 
}

答案 4 :(得分:0)

您所描述的场景正是延迟加载的设计目标。

您希望显示包含摘要信息的列表,并在需要时加载较重的内容。这是延迟加载。它是“懒惰的”,因为它避免在绝对需要之前做额外的工作。

你想要的是JrmDocumentContent被懒惰地加载,你很顺利。要得到这个,你必须删除lazy = false。 lazy = true是nhibernate中的默认值,但你可以放置lazy = true来确定。你必须恢复虚拟。

像这样或任何属性懒洋洋地加载blob,我认为现在通过在属性定义上设置lazy = true来支持nhibernate的最新版本。

通过将重内容分成单独的类/表而使用的方法是之前懒惰加载blob的唯一方法。我不知道你使用的是什么版本的nhibernate,但你所采用的策略是正确的。你应该接受延迟加载。您还需要在JrmDocumentContent类的Content属性中删除lazy = false。除此之外,我认为没有其他理由不起作用。

答案 5 :(得分:0)

我确实遇到过这个问题。

这就是我所做的:

  1. 创建我自己的自定义代理(使用Castle DynamicProxy,但您可以尝试其他代理),在所有未初始化的属性和集合上返回null,并返回每个已初始化集合的副本。我使用这样的代理将每个根对象结果包装在我的服务中。将此代理作为我的服务的返回值传递 - 几乎可以工作,除了我无法让我的代理本身正确序列化。这就是我尝试方法2的原因:

  2. (可怕)将我的所有实体深深地克隆到新对象中,跳过未初始化的属性和集合。这很有效,但很糟糕。

  3. 目前我正在尝试使用DataContractSurrogate来解决1中的问题,或者完全取代代理的使用。我目前要解决的问题是你不能“过滤”对象属性 - 你不能从GetObjectToSerialize返回null - 这正是我想要返回的对象是serialized是一个未初始化的NHibernate代理或集合。

  4. 我进步时会更新这个答案。目前我正在使用解决方案2作为临时解决方法。我会分享这些代码,但目前这是一团糟(因为我并不打算将深度克隆作为解决方案)。