C#如何将存储过程返回的数据填充到Person类的内部PhoneNumber对象
解决方案
你可以选择以下两种方案实现映射,根据你使用的EF Core版本选择即可:
方案1:中间DTO承接映射(兼容所有EF Core版本,最稳妥)
先定义和存储过程返回字段完全匹配的无键DTO承接查询结果,再手动映射到Person实体。
1.1 定义基础实体
public class PhoneNumber { public string AreaCode { get; set; } public string Phone { get; set; } public string Extension { get; set; } } public class Person { // 个人基础信息示例 public int Id { get; set; } public string Name { get; set; } // 地址信息示例 public string Address { get; set; } // 电话属性 public PhoneNumber BusinessPhone { get; set; } public PhoneNumber ResidencePhone { get; set; } }
1.2 定义存储过程承接DTO
public class PersonSpDTO { public int Id { get; set; } public string Name { get; set; } public string Address { get; set; } // 商务电话字段和存储过程返回完全匹配 public string BusinessAreaCode { get; set; } public string BusinessPhone { get; set; } public string BusinessExtension { get; set; } // 住宅电话字段和存储过程返回完全匹配 public string ResidentialAreaCode { get; set; } public string ResidentialPhone { get; set; } public string ResidentialExtension { get; set; } }
1.3 配置DbContext
在DbContext的OnModelCreating方法中配置DTO为无键实体:
modelBuilder.Entity<PersonSpDTO>().HasNoKey();
1.4 查询并映射
var people = context.Set<PersonSpDTO>() .FromSqlRaw("EXEC GetPersonDetails") .AsEnumerable() .Select(dto => new Person { Id = dto.Id, Name = dto.Name, Address = dto.Address, BusinessPhone = new PhoneNumber { AreaCode = dto.BusinessAreaCode, Phone = dto.BusinessPhone, Extension = dto.BusinessExtension }, ResidencePhone = new PhoneNumber { AreaCode = dto.ResidentialAreaCode, Phone = dto.ResidentialPhone, Extension = dto.ResidentialExtension } }) .ToList();
方案2:构造函数映射(仅支持EF Core 8及以上版本,代码更简洁)
直接在Person实体中定义匹配存储过程返回字段的构造函数,在构造函数内部完成PhoneNumber对象的初始化,不需要中间DTO。
2.1 改造Person实体增加构造函数
public class Person { // 构造函数参数名和存储过程返回字段名完全匹配(不区分大小写) public Person(int id, string name, string address, string businessAreaCode, string businessPhone, string businessExtension, string residentialAreaCode, string residentialPhone, string residentialExtension) { Id = id; Name = name; Address = address; BusinessPhone = new PhoneNumber { AreaCode = businessAreaCode, Phone = businessPhone, Extension = businessExtension }; ResidencePhone = new PhoneNumber { AreaCode = residentialAreaCode, Phone = residentialPhone, Extension = residentialExtension }; } // 原有属性保持不变 public int Id { get; set; } public string Name { get; set; } public string Address { get; set; } public PhoneNumber BusinessPhone { get; set; } public PhoneNumber ResidencePhone { get; set; } }
2.2 直接查询
var people = context.Set<Person>() .FromSqlRaw("EXEC GetPersonDetails") .ToList();
注意事项
- 存储过程返回的字段名需要和接收的DTO属性/构造参数名完全匹配,EF Core映射时不区分大小写
- 若返回字段可能为null,建议将PhoneNumber的属性设置为可空类型,避免空引用异常
- 使用无键DTO的方案兼容所有EF Core版本,适用范围更广;构造函数映射方案仅支持EF Core 8及以上版本,代码更简洁
内容的提问来源于stack exchange,提问作者CrazyCoder
相关产品推荐
相关产品推荐

