Сопоставление AutoMapper со свойством обнуляемого свойства - PullRequest
10 голосов
/ 04 ноября 2010

Как можно сопоставить свойство с подчиненным свойством, которое может быть нулевым?

например, следующий код завершится с ошибкой NullReferenceException, поскольку свойство пользователя контакта имеет значение null.

using AutoMapper;

namespace AutoMapperTests
{
    class Program
    {
        static void Main( string[] args )
        {
            Mapper.CreateMap<Contact, ContactModel>()
                .ForMember( x => x.UserName,  opt => opt.MapFrom( y => y.User.UserName ) );

            Mapper.AssertConfigurationIsValid();

            var c = new Contact();

            var co = new ContactModel();

            Mapper.Map( c, co );
        }
    }

    public class User
    {
        public string UserName { get; set; }
    }

    public class Contact
    {
        public User User { get; set; }
    }

    public class ContactModel
    {
        public string UserName { get; set; }
    }
}

Я бы хотел, чтобы в качестве имени пользователя ContactModel по умолчанию использовалась пустая строка.

Я пробовал метод NullSubstitute, но я предполагаю, что он пытается работать с User.Username, а не только со свойством User.

Ответы [ 3 ]

20 голосов
/ 04 ноября 2010

Вы можете написать код отображения следующим образом:

Mapper.CreateMap<Contact, ContactModel>()
            .ForMember( x => x.UserName,  opt => opt.MapFrom( y => (y.User != null) ? y.User.UserName : "" ) );

Это проверит, является ли User нулевым или нет, а затем назначит либо строку emtpy, либо UserName.

6 голосов
/ 05 декабря 2010

Если вы обнаружите, что делаете много нулевых проверок, как в ответе Дейва, вы можете рассмотреть возможность применения техники, о которой я писал в блоге некоторое время назад: Избавиться от нулевых проверок в цепочках свойств . Это позволит вам написать это:

Mapper.CreateMap<Contact, ContactModel>()
    .ForMember(x => x.UserName,
        opt => opt.NullSafeMapFrom(y => y.User.UserName) ?? string.Empty);
3 голосов
/ 27 апреля 2011

Решением, которое я использовал, является создание замыкания вокруг исходного делегата, который оборачивает его в блок try / catch. К сожалению, необходимо использовать Expression.Compile(), чтобы помешать Visual Studio перехватить исключение при его создании в исходном делегате. Вероятно, не рекомендуется в высокопроизводительных средах, но у меня никогда не было проблем с его использованием в обычном интерфейсе. Ваш пробег может варьироваться.

Метод расширения

public static class AutoMapperExtensions
{
    public static void NullSafeMapFrom<T, TResult>(this IMemberConfigurationExpression<T> opt, Expression<Func<T, TResult>> sourceMemberExpression)
    {
        var sourceMember = sourceMemberExpression.Compile();

        opt.MapFrom(src =>
        {
            try
            {
                return sourceMember(src);
            }
            catch (NullReferenceException)
            {}

            return default(TResult);
        });
    }
}

Использование

.ForMember(dest => dest.Target, opt => opt.NullSafeMapFrom(src => src.Something.That.Will.Throw));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...