我有一个包含汽车历史记录的数据库。每个汽车历史记录都有多个与其相关的图像。我使用NHibernate 2.2来设置关系,CarHistory映射包含一个图像包:
<bag name="Photos" table="DetailPhoto" cascade="all" lazy="true">
<key column="CAR_DETAIL_ID"/>
<one-to-many class="DetailPhoto"/>
</bag>
我有一个iPad应用程序,它使用JSON与服务器通信。我想将所有的汽车历史记录项目加载到iPad上的列表中,并且我不想在加载列表时包括照片,因为这会减慢数据检索速度,这就是为什么我让照片变得懒惰的原因。
当我尝试使用JsonConvert.SerializeObject序列化我的汽车历史记录列表时,我会遇到一个延迟初始化异常,这是因为我已经加载了我的对象并关闭了会话,因为我不需要照片,而且JsonSerializer正在接触对象上的所有属性。
我想在不带照片的情况下将Json数据返回给客户端,但我不能在对象上使用ignore JsonProperty,因为我想在其他情况下加载此集合。
我已经尝试过了,但它只是做了同样的事情,给了我懒惰的初始化异常:http://www.royjacobs.org/2011/07/27/using-json-net-to-serialize-proxied-nhibernate-objects/
这是我的CarHistory(CarDetail)类
public class CarDetail
{
[JsonProperty("id")]
public virtual int Id { get; set; }
[JsonProperty("carId")]
public virtual int CarId { get; set; }
[JsonProperty("date")]
public virtual DateTime ? Date { get; set; }
[JsonProperty("details")]
public virtual string Details { get; set; }
[JsonProperty("photos")]
public virtual IList<DetailPhoto> Photos { get; set; }
}
所以我的问题是,在某些情况下,如果没有相关的照片,我如何检索CarHistorias列表?
对于这样的情况,您通常希望在您的"连接的";域对象和序列化格式。我通常创建一个数据传输对象,它类似于域模型对象,但通常没有直接关联,而是只有ID列表。然后我使用Automapper在数据传输对象和域对象之间进行映射。
默认的合约序列化程序尝试序列化所有内容,当它遇到尚未加载的内容时,它不会识别它并尝试序列化它。这反过来迫使代理尝试加载数据,这会导致性能问题(1+n+n^2+..查询),或者直接抛出异常(当会话已经关闭时)——这就是您首先观察到的。
使用自定义协定解析器,您将能够指示序列化程序不序列化未加载的集合和属性。或者抛出一个异常,或者记录它,无论你想在你的情况下做什么。
请参阅类似的问题:NHibernate代理的JSON.Net序列化(NH 3.3.2.4000)-您可以在那里找到自定义ContractResolver的示例。
不过,它并不完全符合您的需求,因为您的问题不同,所以在编写自己的ContractResolver时,您应该在其中筛选要序列化的属性,例如:
var propertyInfo = (PropertyInfo)member;
var value = propertyInfo.GetValue(target);
var shouldSerialize = NH.NHibernateUtil.IsInitialized(value);
当属性包含已代理但尚未加载的集合或对象引用时,它将生成CCD_ 1。