AutoMapper映射到可空属性的属性

时间:2010-11-04 00:28:17

标签: c# automapper

如何将属性映射到可能为null的子属性?

例如,以下代码将因NullReferenceException而失败,因为Contact的User属性为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的UserName默认为空字符串。

我尝试过NullSubstitute方法,但我认为它试图使用User.Username,而不是仅仅在User属性上。

3 个答案:

答案 0 :(得分:20)

您可以编写如下映射代码:

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

这将检查User是否为空,然后分配一个emtpy字符串或UserName

答案 1 :(得分:6)

如果您发现自己在Dave的答案中进行了大量的空检查,您可能会考虑应用我刚才发表的博客技术:Getting rid of null checks in property chains。这将允许你写这个:

Mapper.CreateMap<Contact, ContactModel>()
    .ForMember(x => x.UserName,
        opt => opt.NullSafeMapFrom(y => y.User.UserName) ?? string.Empty);

答案 2 :(得分:3)

我使用的解决方案是在原始委托周围创建一个闭包,它将它包装在try / catch块中。遗憾的是,必须使用Expression.Compile()来阻止Visual Studio在原始委托中抛出异常时捕获异常。可能不建议在高性能环境中使用,但我在常规UI中使用它时从未遇到过任何问题。你的milage可能会有所不同。

扩展方法

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));