views:

465

answers:

3

Ok, so I was part way through the long winded process of creating DTOs for sending my model over the wire and I don't feel like I'm going down the right route.

My issue is that most of the entities in my model are not much more that DTOs anyway. I basically have an anaemic domain model, which is fine but it also make me wonder if I need to model DTOs for these entities.

So my first question is what issues might I hit if just serialize my entities and pass these about over the wire?

Secondly, a more specific question is given a property signature like so:

public virtual Unit Unit { get; set; }

Is it possible for me just to send over the wire the UnitId and not the serialized unit object?

Edit: Sorry I wasn't clear enough with my question, as you guys have posted I know that I can specify only the Id property of unit but this wont work for me.

The reason is that this property (above) is on a "Country" class and I want the UnitID only returning when I call "CountryService.GetCountry(Id)" or simmilar. BUT on the floowing service call "UnitService.GetUnit(Id)" I want more properties to be serialized and sent over the wire. Hope this makes sense.

Thanks, Chris.

+1  A: 

Secondly, a more specific question is given a property signature like so:

public virtual Unit Unit { get; set; }

Is it possible for me just to send over the wire the UnitId and not the serialized unit object?

Sure - make sure to

  1. not mark your Unit property with a [DataMember]
  2. create a second property called UnitId which you do mark as data member
  3. make sure your clients can always somehow reconstruct the Unit class from only it's UnitId

UPDATE:

The reason is that this property (above) is on a "Country" class and I want the UnitID only returning when I call "CountryService.GetCountry(Id)" or simmilar. BUT on the floowing service call "UnitService.GetUnit(Id)" I want more properties to be serialized and sent over the wire. Hope this makes sense.

In that case, you need two separate DataContracts - one for the CountryService.GetCountry(Id) call with just the UnitId in it, and another one for the UnitService.GetUnit(Id) call with all the properties of Unit that you want in it.

You cannot conditionally send some properties - or not - depending on a runtime decision. DataContracts are modelled in XML schema, and that is pretty static. If you have two sets of properties that you need, you need two separate DataContracts.

marc_s
A: 

You can downsize the object that will be passed over the wire by adding the NonSerializedAttribute (msdn). You will still get Unit, but only with the UnitId.

I don't think there would be a problem in just serializing your DTO's. Do you use all of the information in your DTO's? Are you crossing domain boundaries? I would create new entities in every domain and make mappers for them.

Michel van Engelen
A: 

From what I can understand, your problem stems from the fact that you have a local explicitly declared object graph made from your DTOs. What I mean is that you have declared public Unit Unit { get; set; } on your Country model (not sure why you're declaring them virtual but that's not directly related to the issue at hand) rather than trying an approach that guarantees simplicity of the object graph into the degenerate case of a single object graph node.

For example, consider defining every "reference" property on your model in the form public UnitID Unit { get; set; } where UnitID might actually be int or Guid or whatever you use to uniquely identify and distinguish Unit models from each other. Wherever you have a reference or set of references to another model, replace it with its identifier type instead of its actual type. This strategy lends itself well to a persisted set of models e.g. from/to a database with identity keys for each model. Doing this gets you simplicity of serialization without having to worry about circular references because they are now impossible. Technically, there are no more references (i.e. direct references; they are now indirect references). We're now just adding a layer of indirection in your domain model design. Now let's accommodate for that layer of indirection.

Since you've claimed that you're fine with the anemic domain model approach then this should fit well with that. You pay the minor (IMHO) cost of indirection in your model design and trade it up for the major (IMHO) benefits of an interface-based approach to data retrieval:

public interface IUnitRepository {
    Unit GetUnit(UnitID id);
    IEnumerable<Unit> GetUnits(IEnumerable<UnitID> ids);
    // etc.
}

In your consumer code (i.e. the code that consumes this interface and your Unit domain models), it only looks slightly more complex to traverse the implied object graph by performing interface calls to get the underlying models pointed to by the indirect references.

BEFORE:

Country ct = ...;    // I assume you have this reference already
Unit ut = ct.Unit;

AFTER:

// Somewhere earlier in your code, i.e. not *every* time this type of code appears
IUnitsRepository repo = new SomeUnitsRepositoryImpl();
Country ct = ...;    // I assume you have this reference already
Unit ut = repo.GetUnit(ct.UnitID);

If this bothers you syntactically, you can define a set of extension methods typed on Country of the form:

public static Unit Unit(this Country c, IUnitsRepository repo) {
    return repo.GetUnit(c.UnitID);
}

AFTER EXTENSION METHODS:

IUnitsRepository repo = new SomeUnitsRepositoryImpl();
Country ct = ...;    // I assume you have this reference already
Unit ut = ct.Unit(repo);

The interface-based approach gets you the classical set of benefits such as separation of concerns, testability, consumer-producer insulation, and many more. Furthermore, you now get more direct control over object lifetime via the implementation type of your interface. What I mean is that you shouldn't have to assume naivety of implementation of your Unit GetUnit(UnitID id) method. This method could now perform some local in-memory caching utilizing a Dictionary<UnitID, Unit> tied with the instance of SomeUnitsRepositoryImpl.

A bit long-winded, but I hope it helps. As if it weren't obvious from the amount of detail provided, I am currently toying with this design at my place of employment for dealing with our system of record database. :) I am really loving all the flexibility it gives me all at the simple cost of adding one level of indirection in the design of the domain models.

James Dunne
Ok, so the reason that the property is virtual is because I am using and ORM (NHibernate in this case) which takes my POCO country object and builds a proxy around it to auto hooks up lazy loading related objects (i.e. unit in this case). Now I could just have the Country object have no relations to any other model as you stated, but it would mean creating all this plumbing work manually. This is not a good trade off for me as I think the serializer should be flexible enough for me to take a complex model and only expose what I choose. I ultimately chose AutoMapper
Owen