开发者

AutoMapper mapping to a property of a nullable property

开发者 https://www.devze.com 2023-01-23 15:44 出处:网络
How can you map a property to a sub-property that may be null? eg the following code will fail with a NullReferenceException because the Contact\'s User property is null.

How can you map a property to a sub-property that may be null?

eg the following code will fail with a NullReferenceException because the Contact's User property is 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; }
    }
}

I'd like ContactModel's U开发者_C百科serName to default to an empty string instead.

I have tried the NullSubstitute method, but I assume that's trying to operate with User.Username, rather than just on the User property.


You could write the mapping code like follows:

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

This will check if the User is null or not and then assign either an emtpy string or the UserName.


If you find yourself doing a lot of null checking like in Dave's answer, you might consider applying the technique I've blogged about a while ago: Getting rid of null checks in property chains. This will allow you to write this:

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


A solution I've used is to create a closure around the original delegate, which wraps it in a try/catch block. It's unfortunately necessary to use Expression.Compile() to stop Visual Studio from catching the exception when it's thrown in the original delegate. Probably not recommended in high performance environments, but I've never had any issue using it in regular UI stuff. Your milage may vary.

Extension method

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

Usage

.ForMember(dest => dest.Target, opt => opt.NullSafeMapFrom(src => src.Something.That.Will.Throw));
0

精彩评论

暂无评论...
验证码 换一张
取 消