Automapper - может ли он отображать только существующие свойства в исходных и целевых объектах?

У меня есть простая функция обновления:

public void Update(Users user)
{
    tblUserData userData = _context.tblUserDatas.Where(u => u.IDUSER == user.IDUSER).FirstOrDefault();
    if (userData != null)
    {
        Mapper.CreateMap<Users, tblUserData>();
        userData = Mapper.Map<Users, tblUserData>(user);
        _context.SaveChanges()
    }
}

userData - это объект EF, и его свойство Entity Key получает нулевое значение, поскольку, я считаю, оно существует в целевом объекте, но не в исходном объекте, поэтому оно получает сопоставление с его значением по умолчанию (для ключа Entity Key, что null)

Итак, мой вопрос в том, может ли Automapper быть настроен только для того, чтобы сопоставлять свойства, существующие как в исходном, так и в целевом объектах? Я бы хотел, чтобы такие вещи, как Ключ сущности и свойства навигации, были пропущены.

Ответ 1

Вы можете явно указать AutoMapper на Ignore определенные свойства, если это необходимо:

Mapper.CreateMap<Users, tblUserData>()
        .ForMember(dest => dest.Id, opt => opt.Ignore());

который будет означать, что столбец идентификатора в целевом объекте ВСЕГДА останется нетронутым.

Вы можете использовать параметр Condition, чтобы указать, применяется ли отображение в зависимости от результата логического условия, например:

Mapper.CreateMap<Users, tblUserData>()
        .ForMember(dest => dest.Id, opt => opt.Condition(src=>src.Id.HasValue));

или

Mapper.CreateMap<Users, tblUserData>()
        .ForMember(dest => dest.Id, opt => opt.Condition(src=>src.Id != null));

в зависимости от ваших конкретных требований.

Ответ 2

Вы можете сказать AutoMapper игнорировать поля, которые вы не хотите отображать так:

userData = Mapper.Map<Users, tblUserData>(user).ForMember(m => m.EntityKey, opt => opt.Ignore());

Ответ 3

Вы можете переопределить это поведение, указав небольшой метод расширения, чтобы игнорировать все свойства, которые не существуют в целевом типе.

public static IMappingExpression<TSource, TDestination> IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
    var sourceType = typeof(TSource);
    var destinationType = typeof(TDestination);
    var existingMaps = Mapper.GetAllTypeMaps().First(x => x.SourceType.Equals(sourceType)
        && x.DestinationType.Equals(destinationType));
    foreach (var property in existingMaps.GetUnmappedPropertyNames())
    {
        expression.ForMember(property, opt => opt.Ignore());
    }
    return expression;
}

Тогда можно сделать отображение следующим образом:

Mapper.CreateMap<SourceType, DestinationType>().IgnoreAllNonExisting();

Также можно настроить этот метод в соответствии с вашими потребностями, например, игнорируя свойства, которые имеют защищенный или закрытый сеттер.