.NET Web API C#:如何通过GET方法仅选择模型部分属性?
问题
需要实现一个GET接口,仅返回User模型的指定属性及关联模型的部分字段:
- 需返回的User属性:IdUser、UserName、UserMail、UserCompany
- 需返回的关联属性:Profession的IdProfession、ProfessionName;ProfessionField的IdProfessionField、ProfessionFieldName
- 排除字段:UserProfessionId、UserProfessionFieldId、UserPicture、DataUsages及关联模型的冗余字段
相关模型代码
User模型
namespace Sims.Models { public partial class User { public User() { DataUsages = new HashSet<DataUsage>(); } public long IdUser { get; set; } public int UserProfessionId { get; set; } public int UserProfessionFieldId { get; set; } public string? UserName { get; set; } public string? UserMail { get; set; } public string? UserCompany { get; set; } public byte[]? UserPicture { get; set; } public virtual Profession UserProfession { get; set; } = null!; public virtual ProfessionField UserProfessionField { get; set; } = null!; public virtual ICollection<DataUsage> DataUsages { get; set; } } }
Profession模型
namespace Sims.Models { public partial class Profession { public Profession() { ProfessionFields = new HashSet<ProfessionField>(); Users = new HashSet<User>(); } public int IdProfession { get; set; } public string ProfessionName { get; set; } = null!; public virtual ICollection<ProfessionField> ProfessionFields { get; set; } public virtual ICollection<User> Users { get; set; } } }
当前实现及问题
当前GET方法代码:
// GET: api/Users [HttpGet] public async Task<ActionResult<IEnumerable<User>>> GetUsers() { return await _context.Users //.Include(u => u.UserProfession) .Select(u => new User { IdUser = u.IdUser, UserName =u.UserName, UserMail = u.UserMail, UserCompany = u.UserCompany, UserProfessionField = u.UserProfessionField }).ToListAsync(); }
返回结果包含大量不需要的字段(如UserProfessionId、DataUsages等),不符合需求。
解决方案
1. 创建DTO(数据传输对象)
定义一个专门用于返回数据的DTO类,只包含需要的字段:
public class UserDto { public long IdUser { get; set; } public string? UserName { get; set; } public string? UserMail { get; set; } public string? UserCompany { get; set; } // 关联Profession的字段 public int ProfessionId { get; set; } public string ProfessionName { get; set; } = null!; // 关联ProfessionField的字段 public int ProfessionFieldId { get; set; } public string ProfessionFieldName { get; set; } = null!; }
2. 修改GET方法
使用Select投影到DTO,同时确保Include关联模型(避免懒加载导致额外查询):
// GET: api/Users [HttpGet] public async Task<ActionResult<IEnumerable<UserDto>>> GetUsers() { return await _context.Users .Include(u => u.UserProfession) .Include(u => u.UserProfessionField) .Select(u => new UserDto { IdUser = u.IdUser, UserName = u.UserName, UserMail = u.UserMail, UserCompany = u.UserCompany, // 映射Profession字段 ProfessionId = u.UserProfession.IdProfession, ProfessionName = u.UserProfession.ProfessionName, // 映射ProfessionField字段 ProfessionFieldId = u.UserProfessionField.IdProfessionField, ProfessionFieldName = u.UserProfessionField.ProfessionFieldName }) .ToListAsync(); }
关键说明
- 不要直接实例化
User类返回:原模型包含大量不需要的字段,即使只赋值部分属性,序列化时仍会输出所有公共属性(未赋值的会显示默认值或null)。 - 必须Include关联模型:如果不使用
Include,EF Core会通过懒加载加载关联数据,导致额外的数据库查询,影响性能;使用Include可以一次性加载所需关联数据。 - 投影到DTO是最佳实践:DTO可以精准控制返回字段,避免暴露敏感数据或冗余信息,同时让API返回结构更清晰。
优化后的返回示例
[ { "idUser": 1, "userName": "user_test", "userMail": "mail@test.com", "userCompany": "TestCompany", "professionId": 1, "professionName": "运动员", "professionFieldId": 1, "professionFieldName": "Sports" }, { "idUser": 2, "userName": "roger_federer", "userMail": null, "userCompany": null, "professionId": 1, "professionName": "运动员", "professionFieldId": 1, "professionFieldName": "Sports" } ]
内容的提问来源于stack exchange,提问作者Cucumberbatch
相关产品推荐
相关产品推荐

