Question

This is a general question about how you deal with ORM models when having to pass them between applications via http and tcp transports, however specifically I'm using NHibernate via Castle Active Record, if it makes any difference. The format of the data over the transport could be JSON or it could be XML.

There are three issues that I run into when passing ORM models over transports:

  1. Circular reference errors upon XML/JSON serialization. These errors can be resolved by using ScriptIgnore and XmlIgnore attributes on relationship properties, however it's not a great solution because sometimes you want to include relationed objects that are ignored, and you could cause circular ref errors elsewhere if you remove the ignore attributes.

  2. Lazy loading upon serialization. Let's say you have class A which has a 1:1 relation to class B. You serialize class A, and it will try to call the db to get and serialize class B. Sometimes you are no longer in a proper session that allows lazy loading at the point of serializing and that throws errors. This can be resolved with the ignore attributes too, but isn't a good solution for the same reason.

  3. Base classes of ORM models aren't serializable to XML but are sealed. I don't know of any solution to this one, but I've run into it many times.

One solution to the issues above is to not pass ORM models back and forth across transports at all, and I've heard many say that is the recommended solution. However, how do you then do this in a clean manner? Let's say you have ModelA, which you want to pass from one app to another using some sort of transport.

  1. You create a ModelAView class, which has all of the properties of ModelA except without all of the ORM attributes, base classes, and lazy loading features. Already the solution isn't clean, as you now have 2 classes with the same duplicated properties. When you want to make a change to the model, you will have to change it in both classes.

  2. You grab a ModelA instance from the database and have to field-by-field populate the properties of the ModelAView. Maybe you have a constructor for ModelAView which passes in a ModelA instance, and sets the properties in there so it's a little cleaner. However you're still having to set the values property by property, which can be cumbersome. You can try to do some sort of clone functionality, however if it has child objects then you need to deep clone, and it doesn't seem like there's a good way to do this, especially since the View class won't necessarily have all of the same properties that the ModelA class does.

  3. You pass ModelAView over the transport to the other app.

  4. The other app hopefully can just use ModelAView for whatever it needs to do. However if it needs to update properties of ModelA and save them to the db, then it would need to then do the opposite, copy all the properties from ModelAView to ModelA and then save to the db.

So I've written a lot here, but I hope I've made clear the challenges I'm having with dealing with ORM models in these situations. Does anyone have any experiences they can share on tried and true methods to deal with these issues that don't require code duplication and/or property-by-property copying of values from one object to another?

Était-ce utile?

La solution

I think you're out of luck. I ran into the same issue (lots of people have) and the consensus seems to be that you should use DTO's (Data Transfer Objects). AutoMapper makes it a little easier.

You might save yourself the hassle of converting from Entities to DTO's if you use NH's result transformers to return your results as DTO's.

We ended up creating a couple different DTO's per entity, each one containing different children or collections, e.g. Customer, CustomerWithOrders, etc. The client that needs a DTO has to know what it needs ahead of time so it can request the right kind.

Maintaining it hasn't been too bad though, since our entities don't change much.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top