简体   繁体   中英

JSON.NET and nHibernate, ignore lazy loaded objects when serializing

I have a database with Car Histories. Each car history has multiple images associated with it. I am using NHibernate 2.2 to set up the relationships and the CarHistory mapping contains a bag for the images:

<bag name="Photos" table="DetailPhoto" cascade="all" lazy="true">
  <key column="CAR_DETAIL_ID"/>
  <one-to-many class="DetailPhoto"/>
</bag>

I have an iPad app which communicates with the server using JSON. I want to load all of the car history items into a list on the iPad and I don't want to include the photos when loading the list because it slows down the data retrieval which is why I have made the Photos lazy.

When I try and use JsonConvert.SerializeObject to serialize my list of Car Histories I get a lazy initialization exception which is because I have loaded my objects and closed the session already because I don't need the photos and the JsonSerializer is touching all of the properties on the object.

I would like to return the Json data to the client without the photos but I cannot use the ignore JsonProperty on my object because I want to load this collection in other situations.

I have tried this but it just does the same thing giving me the lazy initialization exception: http://www.royjacobs.org/2011/07/27/using-json-net-to-serialize-proxied-nhibernate-objects/

This is my CarHistory (CarDetail) class

 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; }
}

So my question is how can I retrieve a list of CarHistories without the associated Photos in some circumstances and not others?

For cases like this you often want to come up with a layer in-between your "connected" domain objects and the serialization format. I usually create a data transfer object, which is similar to the domain model object, but usually doesn't have direct associations and instead just has lists of IDs. I then use Automapper to map between the data transfer object and the domain object.

The default contract-serializer tries serializing everything, and when it hits a thing-not-yet-loaded, it does not recognize it and attempts to serialize it. That in turn forces the proxy to attempt loading the data, which causes performance problems (1 + n + n^2 + .. queries) or simply straight away throws an exception (when session's already closed) - and that's what you have observed in the first place.

Using a custom the contract-resolver, you will be able to instruct the serializer to not serialize collections and properties that were not loaded. Or throw your better an exception, or log it, whatever you want in your case.

See similar problem: JSON.Net Serialization of NHibernate Proxies (NH 3.3.2.4000) - you can find there an example of a custom ContractResolver.

It's not complete for your needs though, since your problem is different, so when writing your own ContractResolver, inside it you should filter properties-to-be-serialized by, for example:

var propertyInfo = (PropertyInfo)member;
var value = propertyInfo.GetValue(target);
var shouldSerialize = NH.NHibernateUtil.IsInitialized(value);

which produces false when the property contains a collection or object-reference that was proxied and was not loaded yet.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM