简体   繁体   中英

AutoMapper mapping to a property of a nullable property

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM