简体   繁体   English

实体框架 - 对选定条目的嵌套 Select 查询

[英]Entity Framework - Nested Select Query on Selected Entry

I am using Entity Framework Core 3.1.4 .我正在使用Entity Framework Core 3.1.4 My Model is like-我的 Model 就像-

public class Review
{
    [Key, Required]
    public Guid Id { get; set; }

    public int Rating { get; set; }
    public DateTime WatchDate { get; set; }

    public virtual Guid UserId { get; set; }
    public virtual User User { get; set; }
}

My controller is like this-我的 controller 是这样的——

public async Task<IActionResult> Index()
{
    var data = await _context.Reviews
                        .Include(r=>r.User)
                        .Select(r => new Review {
                            Id = r.Id,
                            WatchDate = r.WatchDate,
                            User = r.User,
                            Rating = r.Rating
                        })
                        .OrderByDescending(r => r.Rating)
                        .ToListAsync();
    return View(data);
}

It is doing fine, but it is querying all data of the User table like this (red marked areas)-它做得很好,但它正在像这样查询User表的所有数据(红色标记区域) -

在此处输入图像描述

But I need only email , so I like to select only email (yellow marked one) from there.但我只需要email ,所以我喜欢 select 从那里只 email (黄色标记一个)。 I am doing Select in the upper level, but can't do the same thing in the inside element.我在上层做Select ,但不能在内部元素做同样的事情。 As far as I know, there was a way in Entity Framework like this .据我所知, Entity Framework中有这样的方法。 But the code is not working as version changed.但是随着版本的变化,代码不起作用。

Can anyone please help, how can I accomplish it?谁能帮忙,我该如何完成?

How can I include only user email in the list, not all data?如何在列表中仅包含用户 email,而不是所有数据? So how can I select nested entry?那么我怎样才能 select 嵌套条目呢?

Try next:接下来试试:

var data = await _context.Reviews
                    .OrderByDescending(r => r.Rating)
                    .Select(r => new Review {
                        Id = r.Id,
                        WatchDate = r.WatchDate,
                        User = new User { Email = r.User.Email},
                        Rating = r.Rating
                    })                       
                    .ToListAsync();

But I would say better design would be to create specific DTO which will contain only needed properties and fill it in the Select clause.但我想说更好的设计是创建特定的DTO ,它只包含所需的属性并将其填充到Select子句中。

Also .Include(r=>r.User) call is not needed cause you have Select clause.此外.Include(r=>r.User)调用,因为您有Select子句。

You need to map your entity in a dto (data transfer object) with exactly same fields, less User, where you add as parameter only UserEmail您需要 map 您的实体在具有完全相同字段的 dto(数据传输对象)中,少用户,您只添加作为参数的用户电子邮件

public async Task<IActionResult> Index()
{
    var data = await _context.Reviews
                        .Include(r=>r.User)
                        .Select(r => new Dtos.Review {
                            Id = r.Id,
                            WatchDate = r.WatchDate,
                            UserEmail = r.User.Email,
                            Rating = r.Rating
                        })
                        .OrderByDescending(r => r.Rating)
                        .ToListAsync();
    return View(data);
}

So, Reviews from Context have type Review Entity , but new Review from your query have type Dto (both have same parameters, less User)因此,来自Context评论具有类型Review Entity ,但来自您的查询的新评论具有类型Dto (两者具有相同的参数,较少的用户)

Anyway, a best practice is to not send entities directly to clients and map it into a dto.无论如何,最佳实践是不要将实体直接发送给客户端,并将 map 发送到 dto。

Entity:实体:

public class Review {
  public int Id {get; set;}
  public DateTime WatchDate {get; set;}
  public int UserId {get; set;}
  public User User {get; set;}
  public decimal Rating {get; set;}
}

Dto: Dto:

public class Review {
  public int Id {get; set;}
  public DateTime WatchDate {get; set;}
  public string UserEmail {get; set;}
  public decimal Rating {get; set;}
}

It's always better to use ViewModel for the view.ViewModel用于视图总是更好。 So First, make a ViewModel class as follows:所以首先,制作一个ViewModel class 如下:

public class ReviewViewModel
{
    public Guid Id { get; set; }

    public int Rating { get; set; }
    public DateTime WatchDate { get; set; }

    public Guid UserId { get; set; }
    public string UserEmail { get; set; }
}

Then project your query to the ViewModel type as follows:然后将您的查询投影到ViewModel类型,如下所示:

public async Task<IActionResult> Index()
{
    var data = await _context.Reviews
                        .Select(r => new ReviewViewModel {
                            Id = r.Id,
                            WatchDate = r.WatchDate,
                            Rating = r.Rating,
                            UserId = r.User.Id,
                            UserEmail = r.User.Email,
                        })
                        .OrderByDescending(r => r.Rating)
                        .ToListAsync();
    return View(data);
}

As a best practice , I would suggest to create a DTO , which only contains the necessary data and not the database objects:作为最佳实践,我建议创建一个 DTO ,它只包含必要的数据而不是数据库对象:

public class UserReviewDTO
{
    public Guid Id { get; set; }
    public int Rating { get; set; }
    public DateTime WatchDate { get; set; }
    public string UserEmail { get; set; }
}

You can make your query like this:您可以像这样进行查询:

var data = await _context.Reviews
    .Select(r => new UserReviewDTO {
        Id = r.Id,
        WatchDate = r.WatchDate,
        UserEmail = r.User.Email,
        Rating = r.Rating
    })
    .OrderByDescending(r => r.Rating)
    .ToListAsync();

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

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