简体   繁体   English

如何在DTO中映射相关DTO的列表:嵌套DTO映射

[英]How to map a list of related DTOs in a DTO: Nesting DTO mapping

Suppose you have a fully defined relationship of books and authors in a large database with many other relationships 假设您在大型数据库中拥有书籍和作者的完全定义的关系,还有许多其他关系

public class Book
{
   public int Id { get; set; }
   public string Title { get; set; }
   ...
   Public int AuthorId { get; set; }
   Public Author Author { get; set; }
}

public class Author
{
   public int Id { get; set; }
   public int GroupId { get; set; }
   public string Name { get; set; }
   ...
   public List<Book> Books { get; set; }
   ...
}

And in your controller you want to return a list of authors, each containing the list of books associated with them using DTOs. 并且在您的控制器中,您想返回一个作者列表,每个作者都包含使用DTO与他们相关联的书籍的列表。

public class BookDTO
{
   public int Id { get; set; }
   public string Title { get; set; }
}

public class AuthorDTO
{
   public int Id { get; set; }
   public string Name { get; set; }
   public List<BookDTO> Books { get; set; }
}

What is the right way to generate that list of DTOs within a DTO? 在DTO中生成DTO列表的正确方法是什么?

Could you do something like this? 你能做这样的事情吗?

var author = from a in _context.authors.Where(a => a.groupId == someGroup)
   select new AuthorDTO()
   {
      Id = a.Id,
      Name = a.Name,
      Books = (from b in a.Books
         select new BookDTO()
         {
            Id = b.Id,
            Title = b.Title
         }).ToList()
   };

Or maybe something like this? 或者也许是这样?

var author = from a in _context.authors.Where(a => a.groupId == someGroup)
   select new AuthorDTO()
   {
      Id = a.Id,
      Name = a.Name,
      Books = (from b in _context.books.Where(b => b.AuthorId == a.AuthorId)
         select new BookDTO()
         {
            Id = b.Id,
            Title = b.Title
         }).ToList()
    };

EDIT: 编辑:

To hopefully be a bit clearer, I rephrased and reposed my question here: 为了更清楚一点,我在这里改写并提出了我的问题:

How to return list of DTO with nested lists of related DTO 如何使用相关DTO的嵌套列表返回DTO列表

What I mean is that you can do something as the following: 我的意思是您可以执行以下操作:

var q = from b in Books
        group b by b.Author into g
        select new AuthorDTO 
        { 
           Name = g.Key.Name, 
           Books = g.Select(gi => new BookDTO { Title = gi.Title })
        };

For this, instead of declaring Books as List<BookDTO> declare it as IEnumerable<BookDTO> . 为此,不要将Books声明为List<BookDTO> ,而是将其声明为IEnumerable<BookDTO>

You can do this using AutoMapper . 您可以使用AutoMapper进行此操作。 You don't need to repeat yourself everywhere. 您无需到处重复。 You'll need to add Profile so the mapping will work each time you caller the IMapper.Map function. 您将需要添加Profile以便每次调用IMapper.Map函数时映射都将起作用。

See this example 看这个例子

  public class BookDTO
  {
     public int Id { get; set; }
     public string Title { get; set; }

     public class MapProfile:AutoMapper.Profile{
          public MapProfile(){
              CreateMap<Book,BookDTO>().ReverseMap();
          }
     }
  }

  public class AuthorDTO
  {
     public int Id { get; set; }
     public string Name { get; set; }
     public List<BookDTO> Books { get; set; }


     public class MapProfile:AutoMapper.Profile{
          public MapProfile(){
              CreateMap<Author,AuthorDTO>()
              .ForMember(dest.Id, opt => opt.MapFrom(src.Id))
              .ForMember(dest.Name, opt => opt.MapFrom(src.Name))
              .ForMember(dest.Books, opt => opt.MapFrom(src.Books));
          }
     }
  }

now in your controllers you need to inject IMapper to be able to use IMapper.Map<TSource, TDestination> method. 现在,在您的控制器中,您需要注入IMapper才能使用IMapper.Map<TSource, TDestination>方法。

     public class AuthorController : Controller{

         private readonly IMapper mapper;
         private readonly Context context;

           public AuthorController(IMapper mapper, Context context){
                 mapper =mapper;
                //...context=context;
           }
           public IActionResult Index(){
              var authors = context.Author.Include(a=>a.Book).ToList();
             var authorDTOs = mapper.Map<List<AuthorDTO>>(authors);
             return View(authorDTOs);
           }
     }

This is Mapper profile example. 这是Mapper配置文件示例。 Profile class comes from Automapper lib. 配置文件类来自Automapper lib。

public class ApplicationServiceAutoMapperProfile : Profile
{
    public ApplicationServiceAutoMapperProfile()
    {
         //Don't use ForMember method if you want to show Id's
         CreateMap<Book, BookDTO>()
            .ForMember(m => m.Id, opt => opt.Ignore());

         CreateMap<Author, AuthorDTO>()
            .ForMember(m => m.Id, opt => opt.Ignore());
    }
}

This is How you can map.GetAuthors Method returns mapped Dtos. 这就是映射方法。GetAuthors方法返回映射的Dto。

public class CustomService {
    private readonly IMapper _mapper;
    private readonly DBContext _context;

    public CustomService(IMapper mapper, DBContext context){
        _mapper = mapper;
        _context = context;
    }

    public IEnumerable<AuthorDTO> GetAuthors(){
        //Automapper automaticaly maps authors's bookdto's also.
        var authors = _context.authors.Where(a => a.groupId == 2).ToList();
        return _mapper.Map<List<AuthorDTO>>(authors);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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