Design pattern for mapping DTOs containing child collections back to domain models
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 th开发者_开发问答is 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?
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.
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).
In hibernate there is a cascade option where the updates from to the children..
I think NHibernate has a similar cascadeAll option.
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:
- Use ConstructWith to pull the entity out of the database using the dto's id.
- Use BeforeMap to CLEAR the entire child collection (make sure that the reference on the child will be set to null as well).
- 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.
精彩评论