views:

519

answers:

3

I'm trying to use AutoMapper to map from DTO's to my Domain.

My DTO's might look like this:

public class MyDTO
{
    public string Name { get; set; }
    public bool OtherProperty { get; set; }

    public ChildDTO[] Children { get; set;}
}

public class ChildDTO
{
    public string OtherName { get; set; }
}

My Domain objects like this:

public class MyDomain
{
    public string Name { get; set; }
    public bool OtherProperty { get; set; }
    public ISet<ChildDomain> Children { get; set; }
}

public class ChildDomain
{
    public string OtherName { get; set; }
}

How would I setup AutoMapper to be able to map from these Array's to Set's. It seems like AutoMapper is taking the Array's and converting them into IList's then failing on conversion to ISet.

Here's the exception

Unable to cast object of type 'System.Collections.Generic.List`1[DataTranser.ChildDTO]' to type 'Iesi.Collections.Generic.ISet`1[Domain.ChildDomain]'.

I'm hoping to find a simple generic way to do this so that I can minimize the infrastructure needed to map from DTO's to Domain. Any help is greatly appreciated.

A: 

The answer:

  1. You have to create your own IObjectMapper to map a custom collection like ISet
  2. Create your own configuration instance with all the standard objectmappers and your new setobjectmapper.
  3. Use an IMappingEngine instance created with the configuration with your own objectmapper instead of the static AutoMapper.Mapper class.

Some remarks:

  • It's easy to configure the IMappingEngine construction in a inversion of control container.
  • The source of automapper itself might help you with creating the IObjectMapper implementation.
  • You are using automapper on the opposite way for what it is designed for: It's designed to map complex objects to simple objects. You try to map a simple DTO to a complex entity. (This does not mean that what you want is hard to do with automapper, but you might get different problems in the future)
  • You are using the anemic domain model anti pattern. Domain should hold all the business logic, so it should not expose a complex collection like ISet (and no public setters for collections at all)
Paco
A: 

So then how would I model MyDomain -> ChildDomain without ending up with an anemic domain model? I understand that without business logic in MyDomain or ChildDomain the domain model is currently anemic, but the goal was to add business logic in as we move forward. I just want to ensure that my View Model can be translated into the domain model and persisted.

What would you suggest for this scenario, moving from a simple mapping between view and domain and later adding in business rules?

Thanks again for your help.

Kas
I don't know, because I model my domain behavior centric and not data centric, data later. I map my viewmodel to domain messages directly calling the entity or calling a domainservice.
Paco
+1  A: 

If your persistence layer is simple, using UseDestinationValue() will tell AutoMapper to not replace the underlying collection:

ForMember(dest => dest.Children, opt => opt.UseDestinationValue())

However, if it's not simple, we just do the updating manually back into the domain. The logic generally gets more complex to update the domain model. Doing reverse mapping puts constraints on the shape of your domain model, which you might not want.

Jimmy Bogard

related questions