20

For the longest time I've been using AutoMapper to both map my domain models to my DTOs, as well as mapping my DTO back to domain models.

I'm using EF4 for my ORM, and this mapping gets really ugly when the model being mapped contains child collections that need to be add/updated/removed from. As I move forward with my project I keep running into this problem more and more: photos for a blog post, packages for an order, etc.

When going from DTO->domain model, I end up having to add a BeforeMap call that removes all the entities from the domain model's collection and then add a custom ValueResolver for the collection that takes the PK of each entity from the DTO, grabs it from the DB (so that Entity Framework doesn't think I'm adding a new entity), and re-adds it to the domain model's collection and then apply any updates to the individual fields.

This is a really ugly solution, but so are my attempts to manually handle updating these collections. Does anyone have any suggestions for a cleaner approach?

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
inolen
  • 607
  • 1
  • 6
  • 10
  • Using Automapper to map your domain models probably means your not using Domain Driven Design. Just saying. – John Farrell Jan 03 '11 at 19:40
  • 1
    Is is unrealistic for me to want to handle this mapping cleanly using some auto-magic mapping solution? Should I instead be creating a service purely for updating my domain models from my DTOs? – inolen Jan 03 '11 at 19:43
  • @jfar how do you figure? First, a domain model isn't synonymous with DDD. Implying that domain models shouldn't be mapped, hand waving this off as "not using Domain Driven Design", and providing no further explanation doesn't seem very helpful, does it? In a layered architecture it's not uncommon to find a service Layer sitting on top of the domain Model. It's also not uncommon for the service layer to talk to the domain, ui and other layers via a tranfer object - helping to keep a "bright line" between these layers. – nerraga Jan 04 '11 at 00:20
  • If you move this mapping into a service layer, then at the very least you'll have isolated the logic that seems be causing you problems (at the cost of having a little more code to maintain). Additionally, automapper is great, but if your mapping is fairly simple then you may consider losing the magic and taking care of it manually. Is it worth your time to wrangle automapper to fit your problem or can you simply replace it in the same amount of time? – nerraga Jan 04 '11 at 00:33
  • I just made a comment @nerraga, not an answer, don't get too excited. – John Farrell Jan 05 '11 at 13:55
  • I'm having exactly the same problem like you. I didn't find a single "best practice" example on the web for this scenario. I have multiple Entities with 1 or more child collections. Adding/updating/removing this kind of entities the manual way is so cumbersome! I also tried to do this with AutoMapper but it didn't work out for me. I can't believe everybody is doing this manually? I hope someone will answer this question. – Simon Jan 16 '11 at 11:18
  • 2
    Was relieved to find this question... disappointed to not find an answer yet :S – DannyT Aug 23 '11 at 22:17
  • 1
    4 years on, and I'm tackling this same issue, and I'm so sad that there is still no decent answer. In fact the OP's suggestion to use BeforeMap to set the primary keys was the best workaround I've found. – David Chiew Oct 20 '15 at 06:15

4 Answers4

3

You may want to use ValueInjecter instead of AutoMapper for this functionality. Check out this question where the makers of both weigh in, AutoMapper vs ValueInjecter . I haven't personally used Value Injecter, but it was built to do what you are trying to do. AutoMapper is better for flattening, but the author of AutoMapper admits that it is not a good tool for "Unflattening", which is what you are trying to do.

Community
  • 1
  • 1
smartcaveman
  • 41,281
  • 29
  • 127
  • 212
1

Because of very bad experience with updating detached object graph I always first load actual object graph from database and manually merge my DTO into this object graph. I usually end up with several helper Merger classes with methods merging DTOs (or view models) to Domain objects. I'm also still looking for better solution.

I also tryed solution where I didn't load object graph from database first. Instead I used custom adapters to build detached domain object graph, attached it to context and set states of all objects and relations. But it was wrong and extremely complex way which couldn't be used for all scenarios (combination of updates and inserts of subentities could not be handled without additional transfered data about initial state).

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • It's good to hear I'm not alone. I feel really bad referencing my concrete repository in my AutoMapper, however, I don't have a desire to start using the IoC just to have those unit testable (I typically take repositories as constructor parameters). I could for complex cases create these service classes just to merge the DTOs back, and I guess continue using AutoMapper for the simple cases, but that sounds sortof weak as well. I'd like to find a consistent design pattern to use across the board. – inolen Jan 05 '11 at 03:11
  • It sounds like the project I am working on is using your second method, we are at a point though where it looks like we will have to switch to querying all detached entities before loading in values from our DTOs. I am against this as it "feels wrong", why should I need to query before running an update? I am wondering if an extended form of Lazy Loading would let me signal the domain which properties on my entities were not set from my DTO and fetch them from the DB if needed. I could T4 template this, but once again it feels like I am writing the Entity Framework for Microsoft... – James Close Nov 24 '11 at 17:02
1

In hibernate there is a cascade option where the updates from to the children..

I think NHibernate has a similar cascadeAll option.

Ajay Reddy
  • 81
  • 3
1

If you can relay on the assumption that the DTO's child collection is probably the most updated version, you can actually replace the old collection with the new one.

We had the same issue with NHibernate and we solved it like this:

  1. Use ConstructWith to pull the entity out of the database using the dto's id.
  2. Use BeforeMap to CLEAR the entire child collection (make sure that the reference on the child will be set to null as well).
  3. AutoMapper will automatically copy the new collection.

Luckily, NHibernate was smart enough to apply changes only, I can't tell if EF does the same. This isn't a perfect solution, but it works for a simple domain model.

Matan
  • 1,437
  • 1
  • 10
  • 6