This is an old version of this article. To see updated version please click on:
In my last post, I explained why it is useful to add base entity class in EF. Today, I will write how with the use of this base class an AutoMapped map collection of data objects (i.e. DTOs to existing collection of entities).
Problem with doing:
AutoMapper removes all entities from entity collection because data item mapped to entity has different hash code and different reference than the original entity. Then when AutoMapper searches for the same item in the original entity collection as mapped entity, it cannot find one. That causes
AutoMapper to add another entity with the same ID as the original, after removing the original entity. Entity collection changed in that way cannot be saved to the database, because EF complains that removed entities have to be removed explicitly from the database on commit.
To fix that problem, we will use a custom
ValueResolver. To create one, we will create a class which will be derived from the
IValueResolver available in the
public interface IValueResolver
ResolutionResult Resolve(ResolutionResult source);
There is also available a
public abstract class ValueResolver<TSource, TDestination> : IValueResolver
public ResolutionResult Resolve(ResolutionResult source);
protected abstract TDestination ResolveCore(TSource source);
But this class makes it available to override only the
ResolveCore method, which will not be sufficient since it does not have information about the destination type of the entity. Without this information, we won't be able to create a generic resolver class. So instead of this class, we will use the interface.
Our generic mapping class has to take two types of parameters: type of data object (DTO) and type of entity. Also, the
ResolutionResult object of the auto mapper mapping context does not have information of which source member is being mapped inside the
ValueResolver. This information has to be passed too. It is best to pass it as an expression instead of a
string, to make it less error prone. To make it possible, we will add a third type parameter which will be the parent type of the data object collection.
public class EntityCollectionValueResolver<TSourceParent, TSource, TDest> : IValueResolver
where TSource : DTOBase
where TDest : BaseEntity, new()
private Expression<Func<TSourceParent, ICollection>> sourceMember;
Expression<Func<TSourceParent, ICollection>> sourceMember)
this.sourceMember = sourceMember;
public ResolutionResult Resolve(ResolutionResult source)
var sourceCollection = ((TSourceParent)source.Value).GetPropertyValue(sourceMember);
if (source.Context.DestinationValue != null)
var destinationCollection = (ICollection<TDest>)
var sourceIds = sourceCollection.Select(i => i.Id).ToList();
foreach (var item in destinationCollection)
foreach (var sourceItem in sourceCollection)
var originalItem = destinationCollection.Where(
o => o.Id == sourceItem.Id).SingleOrDefault();
if (originalItem != null)
return source.New(destinationCollection, source.Context.DestinationType);
var value = new HashSet<TDest>();
foreach (var item in sourceCollection)
source = source.New(value, source.Context.DestinationType);
Expression of type
Expression<Func<TSourceParent, ICollection>> helps us to make sure that inside
Resolve method we will get the correct property without necessity of using existing object source or creating a new one to pass inside some lambda. The
GetPropertyValue method is an extension of object type. It works by taking
MamberExpression from our
Expression<Func<TSourceParent, ICollection>>, and then property
MamberExpression.Member.Name of source member. After that with source property name, we can take its value with reflection:
public static TRet GetPropertyValue<TObj, TRet>(this TObj obj,
Expression<Func<TObj, TRet>> expression,
bool silent = false)
var propertyPath = ExpressionOperator.GetPropertyPath(expression);
var objType = obj.GetType();
var propertyValue = objType.GetProperty(propertyPath).GetValue(obj, null);
public static MemberExpression GetMemberExpression(Expression expression)
if (expression is MemberExpression)
else if (expression is LambdaExpression)
var lambdaExpression = expression as LambdaExpression;
if (lambdaExpression.Body is MemberExpression)
else if (lambdaExpression.Body is UnaryExpression)
Resolve method is enclosed in an
if (source.Context.DestinationValue != null)
This will ensure that we cover two cases when we map a data collection to an existing collection of entities and to a new collection of entities. The second case is inside the
else and is not complicated since it is a simple mapping of all items inside a collection. The interesting part is happening inside the
if and it is composed of three phases:
- Deleting of entities
All entities from destination collection, that are not present inside our data collection, are being deleted. That prevents EF from throwing an error mentioned above. Entities and DTOs have both Ids, which are used to find which of the items was deleted. This is where base entity class is useful since it has Id defined inside.
- Mapping changed items
If entity with the same Id as item in data collection has been found, it is being used as destination of mapping.
- Mapping of new (added) entities, as new objects.
This generic class then can be used as this inside
.ForMember(o => o.DestinationCollection, m =>
ParentDTO, SourceDTO, DestEntity>
(s => s.SourceCollection))
One more thing: this solution will cause
DestEntity mapping profile will try to map again
ParentEntity property inside
DestEntity. Usually child entities has reference to parent entities. If they are not ignored during mapping,
AutoMapper will try do mapping:
ParentDTO which will cause circular mapping.
Also this resolver will not cover the case when Destination Collection is a collection of derived items from parent item. For example, when you have a collection of people with students and teachers inside it, this will try to do mapping only for people. All derived types data will be ignored.
That is all!