Home > Blockchain >  Set up automapper one to many relationship in asp.net core
Set up automapper one to many relationship in asp.net core

Time:11-01

I am started using automapper in my simple project. I want to exactly following 'one-to-many-to-many' mapping :-

public class AppUser
    {
        public int Id { get; set; }
        public string UniversityName { get; set; }
        public ICollection<Post> Posts { get; set; }
    
    }

  public class Post
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public int AppUserId { get; set; }
        public AppUser AppUser { get; set; }
        public ICollection<Postedpic> Postedpics { get; set; }
    }

public class Postedpic
    {
        public int Id { get; set; }
        public string Url { get; set; }
        public string PublicId { get; set; }
        public Post Post { get; set; }
        public int PostId { get; set; }
     
    }

Destination:

 public class MemberDto
    {
        public int Id { get; set; }
        public string UniversityName { get; set; }
        public ICollection<PostDto> Posts { get; set; }
    }

 public class PostDto
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public ICollection<PostedpicDto> Postedpics { get; set; }
    }

 public class PostedpicDto
    {
        public int Id { get; set; }
        public string Url { get; set; }
        public bool IsMain { get; set; }
    }

For proceed with automapper I tried this:-

  CreateMap<AppUser, MemberDto>()
                .ForMember(dest=>dest.Posts,opt=>opt.MapFrom(src=>src.Posts.Select(x=>x.Description)))
                .ForMember(dest=>dest.Posts,opt=>opt.MapFrom(src=>src.Posts.Include(x=>x.Postedpic).Select(x=>x.Postedpic.Url)))
                .ForMember(dest=>dest.Posts,opt=>opt.MapFrom(src=>src.Posts.Include(x => x.Postedpic).Select(x=>x.Postedpic.PublicId)));

But I found this error:- enter image description here

Also I don't understand my approach is right or wrong for proceeding automapper.

CodePudding user response:

Dont use automapper, or any other mapping framework. This is code smell.

Create an interface like:

public interface IMemberDtoCreator {
    int GetId();
    string GetUniversityName();
    ICollection<PostDto> GetPosts();

}

public class MemberDto {

   public int Id { get; set; }
   public string UniversityName { get; set; }
   public ICollection<PostDto> Posts { get; set; }

   public MemberDto(IMemberDtoCreator creator) {
      Id = creator.GetId();
      UniversityName = creator.GetUniversityName();
      Posts = creator.GetPosts();
   }
}

public class AppUser : IMemberDtoCreator {

     public int Id { get; set; }
     public string UniversityName { get; set; }
     public ICollection<Post> Posts { get; set; }

     public int GetId() {
        return Id;
     }

     public string GetUnivsersityName() {
         return UniversityName;
     }

     public ICollection<Post> GetPosts(){
        ICollection<PostDto> result = new ICollection<PostDto>();
        foreach(Post post in Posts){
           result.add(new PostDto(post)) // And repeat the interface implementation for PostDto and post, etc.
        }
    
     }

}

This is pseudo code, and I didn't check for compiling, but you get the idea, I am sure. This is better in every way imaginable.

(If you are worried about overwriting the implementation of your interfaces, simply write the implementations in a partial class. Then you can autogenerate the original "base" class forever, and never interrupt your interface implementations.

CodePudding user response:

You have two issues here:

For the Include method, you need to import the right namespace:

using System.Data.Entity;

You then tell AutoMapper how to do its job. It's smart enough to map properties by name, so you don't need to do much here. You just need to tell it which types to map to:

CreateMap<Post, PostDto>();
            
CreateMap<PostedPic, PostedPicDto>();

CreateMap<AppUser, MemberDto>();        

As for the context, it looks to me like you are using lazy loading and want to make sure the posts and pics are loaded. For this to work, you need to configure the original query with Include, prior to mapping. For instance:

var user = SomeContext.AppUsers
    .Include(u => u.Posts)
    .Include(u => u.Posts.Select(p => p.PostedPics))
    .FirstOrDefault(u => u.Id == someId);

var userDto = mapper.Map<AppUser, MemberDto>(user);
  • Related