3

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?

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

6 Comments

So does this mean that I would need one DTO for the listing of a CarHistory, and a separate DTO for the display of a CarHistory? And in the listing DTO I would ignore the JSON property and in the display DTO I include it? I was trying to avoid this because I would end up with an explosion of DTO and it would make everything more complicated.
The way that I had it was good because on the client side I am using RESTKit which maps the JSON data back into Objective C objects with all of the associations. If I only have IDs I don't think I can do that anymore can I?
You can model the list as a list of CarHistory DTOs in this case, of course, since the item DTO is known and serializable. It's when you get into cases like, for example, the CarId which really should be Car in the domain model. By knowing the Id of the car and having the Car entity known on both sides, you don't then need to serialize it, and therefore you don't need to load it, lazily or otherwise. Once you serialize the DTO and send it, you can deserialize it (using whatever) and reverse map it back to a domain object.
Not true, you do not need to introduce DTOs, you just have to configure the JSON-Serializer properly, see i.e. stackoverflow.com/a/35088817/717732
You do not need to, but if your domain objects are more than just property holders (aka anemic domain model), keeping the state transitions due to deserialization separate from those based on domain logic is more complex than just building DTOs and mapping.
|
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.