0

I have many to many relationship tables such as "User & Notification & UserNotification" and their entities, view models also.

There is only a difference between ViewModel and Entity classes. HasRead property is inside NotificationViewModel. How Can I map this entities to view models? I could not achieve this for HasRead property.

What I did so far is,

Mapping Configuration:

CreateMap<Notification, NotificationViewModel>();
CreateMap<User, UserViewModel>().ForMember(dest => dest.Notifications, map => map.MapFrom(src => src.UserNotification.Select(x => x.Notification)));

Notification class:

public class Notification : IEntityBase
{
    public Notification()
    {
        this.UserNotification = new HashSet<UserNotification>();
    }

    public int Id { get; set; }
    public string Header { get; set; }
    public string Content { get; set; }
    public System.DateTime CreateTime { get; set; }
    public bool Status { get; set; }

    public virtual ICollection<UserNotification> UserNotification { get; set; }
}

User Class

public class User : IEntityBase
{
    public User()
    {
        this.UserNotification = new HashSet<UserNotification>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public string Email { get; set; }
    public string PhoneNumber { get; set; }
    public bool Status { get; set; }

    public virtual ICollection<UserNotification> UserNotification { get; set; }
}

UserNotification class:

public class UserNotification : IEntityBase
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public int NotificationId { get; set; }
    public bool HasRead { get; set; }

    public virtual Notification Notification { get; set; }
    public virtual User User { get; set; }
}

UserViewModel class

public class UserViewModel : IValidatableObject
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public string Email { get; set; }
    public string PhoneNumber { get; set; }
    public bool Status { get; set; }

    public IList<NotificationViewModel> Notifications { get; set; }
}

NotificationViewModel class

public class NotificationViewModel
{
    public int Id { get; set; }
    public string Header { get; set; }
    public string Content { get; set; }
    public System.DateTime CreateTime { get; set; }
    public bool Status { get; set; }
    public bool HasRead { get; set; } // this is the difference
}
Mehmet Ince
  • 4,059
  • 12
  • 45
  • 65
  • I can see you want to map collections, maybe you are missing some additional packages for AutoMapper, see this [answer](https://stackoverflow.com/a/44969907/3122672). – miszczak Jul 12 '17 at 12:24

1 Answers1

2

In order to fix up the HasRead, maybe you can utilize the AfterMap(Action<TSource, TDestination> afterFunction) function. It's not as elegant as the rest of automapper, but it might work.

CreateMap<User, UserViewModel>()
    .ForMember(dest => dest.Notifications, map => map.MapFrom(src => src.UserNotification.Select(x => x.Notification)))
    .AfterMap((src, dest) =>
    {
        foreach (var notificationVM in dest.Notifications)
        {
            notificationVM.HasRead = src.UserNotification.Where(x => x.NotificationId == notificationVM.Id).Select(x => x.HasRead).FirstOrDefault();
        }
    });
grek40
  • 13,113
  • 1
  • 24
  • 50
  • How would this work with ProjectTo? Would that still get HasRead value from DB to the be used in AfterMap? – TWilly Jun 29 '18 at 18:49
  • 1
    @TWilly honestly I don't know, would have to try this (and I don't have time for it right now). However, today I would possibly give a different answer: `CreateMap()` and `CreateMap().ForMember(dest => dest.Notifications, map => map.MapFrom(src => src.UserNotification))`. Then add some more configuration to use the `UserNotification.Notification` as source for most of the properties inside `NotificationViewModel`. – grek40 Jul 02 '18 at 08:45