如何从 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
或其他映射库。它将处理 Nomination
和 User
实体对象到 NominationDto
和 UserDto
对象的映射。那么你就不需要手动完成了。
(我没有测试过上面的代码,但我相信这应该会让你处于一个好的位置。)
编辑
在对我的原始答案发表评论后,我更新了上面代码的 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
这是 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
或其他映射库。它将处理 Nomination
和 User
实体对象到 NominationDto
和 UserDto
对象的映射。那么你就不需要手动完成了。
(我没有测试过上面的代码,但我相信这应该会让你处于一个好的位置。)
编辑 在对我的原始答案发表评论后,我更新了上面代码的 LINQ 部分。
在 .ToListAsync()
.
.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