Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoMapper pass parent reference when mapping child object

I am trying to use AutoMapper to map some DTO (data contract) objects received from a web service into my business objects. The root DTO object contains a collection of child objects. My business object also has a child collection of child business objects. In order to get AutoMapper to work, I had to include a setter on the collection property in my business object or the collection would always be empty. In addition, I had to add a default constructor to the collection type. So, it appears to me that AutoMapper is instantiating a new collection object, populating it and setting as the collection property of my business object.

While this is all well and good, I have additional logic that has to be wired up when the collection is created and having the default constructor defeats the purpose. Essentially, I am establishing the parent-child relationship and wiring up some events so they bubble from child to parent.

What I would like to do is to have AutoMapper simply map the child objects from the DTO's collection to the existing collection on my BO. In other words, skip creating a new collection and simply use the one the business object already has.

Is there any way to easily accomplish this?!?!?

UPDATE

Perhaps a better question, and simpler solution to my problem, is if it is possible to define arguments that AutoMapper will pass to the collection when instantiated? My child collection is defined like this:

public class ChildCollection : Collection<ChildObjects>
{
    public ChildCollection(ParentObject parent) { Parent = parent; }
}

If I can configure AutoMapper to use this constructor and pass in the proper object, that would be PERFECT!

ANOTHER UPDATE

For the sake of clarity, here are the other classes in the problem space:

public class ParentObject
{
    private ChildCollection _children;

    public ChildCollection Children
    {
        get
        {
            if (_children == null) _children = new ChildCollection(this);

            return _children;
        }
    }
}

public class ParentDTO
{
    public ICollection<ChildDTO> Children { get; set; }
}

public class ChildDTO
{
    public String SomeProperty { get; set; }
}

I configure AutoMapper this way:

Mapper.CreateMap<ParentDTO, ParentObject>();
Mapper.CreateMap<ChildDTO, ChildObject>();

Doing so this way and I have to add a setter to the Children property in ParentObject and a default (parameterless) constructor to ChildCollection. While I can work around the need to define the parent-child relationship, it seems that it would be logical to expect AutoMapper to support configuring the map to use a specific constructor when creating the child collection. Something like this:

Mapper.CreateMap<ParentDTO, ParentObject>()
    .ForMember(obj => obj.Children, opt.MapFrom(dto => dto.Children))
    .ConstructUsing(col => new ChildCollection(obj));

Notice that I am passing in the reference to "obj" which is the ParentObject instance being mapped.

like image 641
SonOfPirate Avatar asked Mar 17 '11 15:03

SonOfPirate


1 Answers

It turns out that the answer was right there all along. The UseDestinationValue option does exactly what I want.

This options instructs AutoMapper to use the existing property on the target object and map any child properties or collection items into that object rather than creating a new proxy object.

So, here's all I have to do in my application:

Mapper.CreateMap<ParentDTO, ParentObject>()
    .ForMember(obj => obj.Children,
           opt.UseDestinationValue());

And, voila! Now I can instantiate the child collection, with parent reference, and setup the reference back to the parent in each item as it is added to the collection.

like image 145
SonOfPirate Avatar answered Nov 20 '22 21:11

SonOfPirate