Lazov
Lazov

Reputation: 1476

Automapper, CustomMapping not loading fields of a virtual property

I have the following classes.

 public class SomeModel
        {
            [Key]
            public int Id { get; set; }
            [Required]
            public string UserId { get; set; }
            public virtual User User { get; set; }
            [Required]
            public string Name { get; set; }  
        }

And:

public class SomeModelDetailsResponseModel : IMapFrom<SomeModel>, IHaveCustomMappings
    {
        public int Id { get; set; }
        public string UserId { get; set; }
        public string Name { get; set; }
        public string UserName { get; set; }

        public void CreateMappings(IConfiguration configuration)
        {
            configuration.CreateMap<SomeModel, SomeModelDetailsResponseModel>("name").AfterMap((b, r) =>
            {
                r.UserName = b.User.FirstName + b.User.LastName;
            });
        }
    }

For some reason, when I project an IQueryable of SomeModel to an IQueryable of SomeModelDetailsResponseModel the UserName property turns out to be null.

Upvotes: 0

Views: 917

Answers (1)

Timothy Ghanem
Timothy Ghanem

Reputation: 1616

Assuming these are you class definitions:

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class SomeModel
{
    public int Id { get; set; }
    public string UserId { get; set; }
    public virtual User User { get; set; }
    public string Name { get; set; }
}

public class SomeModelDetailsResponseModel
{
    public int Id { get; set; }
    public string UserId { get; set; }
    public string Name { get; set; }
    public string UserName { get; set; }
}

Solution 1

Do your mapping like this:

var config = new MapperConfiguration(
    cfg =>
    {
        cfg.CreateMap<SomeModel, SomeModelDetailsResponseModel>().AfterMap((b, r) =>
        {
            r.UserName = b.User.FirstName + b.User.LastName;
        });
     });

var mapper = config.CreateMapper();

var response = mapper.Map<SomeModel, SomeModelDetailsResponseModel>(new SomeModel()
{
    User = new User()
    {
        FirstName = "FN",
        LastName = "LN"
    }
});

Since you have your input as IQueryable<SomeModel> and you want to project it into IQueryable<SomeModelDetailsResponseModel>, then you can do this:

var result = q.Select(m => mapper.Map<SomeModel, SomeModelDetailsResponseModel>(m));

where q is your IQueryable<SomeModel> instance.

Solution 2

If you want to use ProjectTo<>, then initialize your mapper as the following:

Mapper.Initialize(cfg =>
{
    cfg.CreateMap<SomeModel, SomeModelDetailsResponseModel>()
        .ForMember(r => r.UserName, c => c.MapFrom(o => o.User.FirstName + o.User.LastName));
});

Then, do your projection as this:

var result = q.ProjectTo<SomeModelDetailsResponseModel>().ToArray();

Where q is your IQueryable<SomeModel>.

Upvotes: 1

Related Questions