如何从 EF Core 中的相关数据中获取很少的属性?

How to get only few properties from related data in EF core?

这是 ASP .net EF Core。

我有 2 个 类。具有一对多关系的提名和用户。

提名将有指向用户 ID 的外键。

类:

public class Nomination
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int NominationId { get; set; }
    public int NomineeUserId { get; set; }
    public int NominationYear { get; set; }

    public User Nominee { get; set; }
}
public class User
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string EmailId { get; set; }
    public byte[] PasswordHash { get; set; }
    public byte[] PasswordSalt { get; set; }
}
public class UserDto
{
    public int UserId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

上下文:

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>().HasKey(x => x.UserId);
        modelBuilder.Entity<User>().Property(x => x.UserId).ValueGeneratedOnAdd();

        modelBuilder.Entity<Nomination>().HasKey(x => x.NominationId);
        modelBuilder.Entity<Nomination>().Property(x => x.NominationId).ValueGeneratedOnAdd();
        modelBuilder.Entity<Nomination>().HasOne(x => x.Nominee).WithMany().HasForeignKey(x => x.NomineeUserId).OnDelete(DeleteBehavior.Restrict);
    }

控制器 GETALL:

public async Task<ActionResult<IEnumerable<Nomination>>> GetNomination()
    {
        return await _context.Nomination
            .Include(n => n.NominationDetails)
            .Include(n => n.Nominee)
            .ToListAsync();
    }

当我为命名执行 GETALL 时,我收到 "Nominee"(用户)的完整对象,包括密码内容。 我需要 UserDTO 而不是 User。我不需要 User

的其他属性

我应该如何更改我的代码来完成此操作?

如果您不使用诸如 AutoMapper 之类的映射库,您可以使用 LINQ 来 select 和 return 一个像这样的新类型:

假设我们也创建了一个 NominationDto

NominationDto.cs

public class NominationDto
{
    public int NominationId { get; set; }
    public int NomineeUserId { get; set; }
    public int NominationYear { get; set; }
    public UserDto Nominee { get; set; }
}
var nominations = _context.Nomination
    .Include(n => n.NominationDetails)
    .Include(n => n.Nominee)
    .Select(nomination => new NominationDto
    {
        NominationId = nomination.NominationId,
        NomineeUserId = nomination.NomineeUserId,
        NominationYear = nomination.NominationYear,
        Nominee = new UserDto
        {
            UserId = nomination.Nominee.UserId,
            FirstName = nomination.Nominee.FirstName,
            LastName = nomination.Nominee.LastName
        }
    }).ToListAsync();

但是,如果可能的话,我建议使用 AutoMapper 或其他映射库。它将处理 NominationUser 实体对象到 NominationDtoUserDto 对象的映射。那么你就不需要手动完成了。

(我没有测试过上面的代码,但我相信这应该会让你处于一个好的位置。)

编辑 在对我的原始答案发表评论后,我更新了上面代码的 LINQ 部分。

.ToListAsync().

之前使用 LINQ 的 .Select() 函数写一个 select 投影

这将创建一个 SQL 查询以仅获取您在 LINQ 中 select 编辑的那些数据库列。

例如提名Dto

public class NominationDto
{
    public int NominationId { get; set; }
    public int NomineeUserId { get; set; }
    public int NominationYear { get; set; }
    public UserDto Nominee { get; set; }
}

您的查询可以是:

var nominations = await _context.Nomination
        .Include(n => n.NominationDetails)
        .Include(n => n.Nominee)
        .Select(nomination => new NominationDto
    {
        NominationId = nomination.NominationId,
        NomineeUserId = nomination.NomineeUserId,
        NominationYear = nomination.NominationYear,
        Nominee = new UserDto
        {
            UserId = nomination.Nominee.UserId,
            FirstName = nomination.Nominee.FirstName,
            LastName = nomination.Nominee.LastName
        }
    }).ToListAsync();

请注意,您可能不需要 .Include(n => n.NominationDetails),因为在此查询中没有从 NominationDetails 中提取/selected/投影任何内容。

此外,如果您不打算跟踪这些实体的更改,那么为了获得更好的性能,您可以在 .Select() 之后和 .ToListAsync() 之前使用方法 .AsNoTracking() 来告诉 EF 您是不会跟踪 EF 对象图中检索到的数据的更改。

您可以在此处找到有关查询跟踪的更多信息:https://docs.microsoft.com/en-us/ef/core/querying/tracking