我在我的数据库中存储了一些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");
}
}
}
答案 0 :(得分:2)
如果您想延迟加载,请在地图中设置lazy =“true”。
答案 1 :(得分:2)
您应该将DTO用于您的服务,并将所有内容保留为lazy = true,而不是序列化您的域模型。这是一个很大的性能提升。
答案 2 :(得分:1)
答案 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)
我确实遇到过这个问题。
这就是我所做的:
创建我自己的自定义代理(使用Castle DynamicProxy,但您可以尝试其他代理),在所有未初始化的属性和集合上返回null
,并返回每个已初始化集合的副本。我使用这样的代理将每个根对象结果包装在我的服务中。将此代理作为我的服务的返回值传递 - 几乎可以工作,除了我无法让我的代理本身正确序列化。这就是我尝试方法2的原因:
(可怕)将我的所有实体深深地克隆到新对象中,跳过未初始化的属性和集合。这很有效,但很糟糕。
目前我正在尝试使用DataContractSurrogate来解决1中的问题,或者完全取代代理的使用。我目前要解决的问题是你不能“过滤”对象属性 - 你不能从GetObjectToSerialize返回null
- 这正是我想要返回的对象是serialized是一个未初始化的NHibernate代理或集合。
我进步时会更新这个答案。目前我正在使用解决方案2作为临时解决方法。我会分享这些代码,但目前这是一团糟(因为我并不打算将深度克隆作为解决方案)。