3
votes

Need automapper to map a domain type's properties back to an existing entity from the context (basically just updating the fields that have changed). I need it to ignore Navigation properties and only map the scalar properties.

I can get it to work if I say ForMember(o => o.MyNavProperty, opt => opt.Ignore) but I'd rather have a generic method for all of my mappings to tell it to only map scalar and not nav properties.

Trying to follow Mauricio's solution:

ASP.net MVC - Should I use AutoMapper from ViewModel to Entity Framework entities?

but I can't get it to successfully ignore my navigation properties.

Here's my updated version:

      private static void CreateMapForEF<TDto, TEntity>()
      {
         Mapper.CreateMap<TDto, TEntity>()
    .ForAllMembers(o => o.Condition(ctx =>
                                       {

                                          var members = ctx.Parent.SourceType.GetMember(ctx.MemberName); // get the MemberInfo that we are mapping

                                          if (!members.Any())
                                             return false;

                                          if (members.First().GetCustomAttributes(
                                                typeof (EdmRelationshipNavigationPropertyAttribute), false).Any())
                                             return false;

                                          return members.First().GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).Any(); // determine if the Member has the EdmScalar attribute set

                                       }));
      }
2

2 Answers

5
votes

I was working on it recently.
You can use the following solution :

Define an Attribute for navigation properties :

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class NavigationPropertyAttribute : Attribute
{
} 

Mark all navigation properties in View-Models with above attribute.

public class TagModel
{
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    public string Description { get; set; }

    [Display(Name = "Image")]
    public string ImagePath { get; set; }

    [NavigationProperty]
    public List<ContentModel> Contents { get; set; }
}

Writing an extension method for AutoMapper to ignore all properties with NavigationProperty attribute.

public static IMappingExpression<TSource, TDestination> IgnoreNavigationProperties<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
    var sourceType = typeof(TSource);

    foreach (PropertyInfo property in sourceType.GetProperties())
    {
        var isNavProp = property.GetCustomAttributes(typeof(NavigationPropertyAttribute), false).Count() == 1;
        if (isNavProp)
                expression.ForMember(property.Name, opt => opt.Ignore());
    }
    return expression;
}

At last you can use it as follows :

Mapper.CreateMap<TagModel, Tag>()
        .ForMember(m => m.Id, opt => opt.Condition(m => m.Id > 0))
        .IgnoreNavigationProperties();
1
votes

I use an explicit approach by adding an interface to the entity and mapping to/from the interface. So rather than exclude I'm being explicit on what to include. The interface is added by declaring a partial class.

The interface is free for me as I use the interface for decoupling, test stubs, mocking etc.

Perhaps just me, but I do not like to see any ignores in an AutoMapper configuration. Can't justify that but it just feels wrong to me.