【问题标题】:How to map a list of related DTOs in a DTO: Nesting DTO mapping如何在 DTO 中映射相关 DTO 列表:嵌套 DTO 映射
【发布时间】:2019-07-18 14:11:31
【问题描述】:

假设您在大型数据库中具有完全定义的书籍和作者关系以及许多其他关系

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; }
   ...
}

在您的控制器中,您希望返回一个作者列表,每个作者都包含使用 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; }
}

在 DTO 中生成 DTO 列表的正确方法是什么?

你能做这样的事吗?

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()
   };

或者可能是这样的?

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()
    };

编辑:

为了更清楚一点,我在这里重新表述并提出了我的问题:

How to return list of DTO with nested lists of related DTO

【问题讨论】:

  • 那么,您希望所有图书按作者分组吗?
  • 是的,基本上就是这样:返回特定作者列表_context.authors.Where(a =&gt; a.groupId == someGroup) 以及一些信息,每个作者 DTO 都包含他们的书籍列表。
  • 所以这是按作者分组的书籍,但我希望书籍列表位于每个作者对象中,并返回该作者列表

标签: c# asp.net-core linq-to-sql entity-framework-core dto


【解决方案1】:

您可以使用AutoMapper 执行此操作。你不需要到处重复自己。 您需要添加Profile,以便每次调用IMapper.Map 函数时映射都会起作用。

看这个例子

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

现在您需要在控制器中注入 IMapper 才能使用 IMapper.Map&lt;TSource, TDestination&gt; 方法。

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

【讨论】:

  • 我正在尝试理解一个没有自动映射器的解决方案
  • 否则你想重新发明轮子?
【解决方案2】:

这是 Mapper 配置文件示例。 Profile 类来自 Automapper 库。

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());
    }
}

这就是你可以如何 map.GetAuthors 方法返回映射的 Dtos。

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

【讨论】:

    【解决方案3】:

    我的意思是您可以执行以下操作:

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

    为此,不要将Books 声明为List&lt;BookDTO&gt;,而是将其声明为IEnumerable&lt;BookDTO&gt;

    【讨论】:

    • 这很酷,我没想到会那样做...但是如果父母列表中包含多个孩子列表怎么办?
    • 如果我理解你所说的想法是一样的,但你需要进行一些连接才能获得你想要的数据。
    • 为了更清楚一点,我在这里重新表述并提出了我的问题:stackoverflow.com/questions/57104588/…
    猜你喜欢
    • 2012-11-23
    • 1970-01-01
    • 1970-01-01
    • 2021-11-07
    • 2021-10-28
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多