AutoMapper未填充数据:Web API Core异步项目问题求助
AutoMapper映射SqlDataReader到Student时属性未填充的解决方法
问题场景
在ASP.NET Core Web API异步项目中,使用AutoMapper将SqlDataReader映射到Student实体,程序无报错且能返回Student实例,但所有属性均未被填充,已确认SqlDataReader包含有效数据。
核心原因
- SqlDataReader未指向有效行:
SqlDataReader初始状态位于结果集起始位置(未指向任何行),直接调用Map方法无法读取数据。 - 缺少DataReader映射支持:AutoMapper默认未启用针对DataReader的映射逻辑,需显式配置相关扩展。
- 重复创建Mapper实例:每次调用
InitializeAutomapper()都会生成新的Mapper实例,既低效也可能隐藏配置问题。
解决方案
1. 先读取Reader行再映射(基础修复)
在调用AutoMapper的Map方法前,必须先调用ReadAsync()将Reader指针移动到有效数据行:
using (var reader = await cmd.ExecuteReaderAsync()) { if (await reader.ReadAsync()) // 移动到第一行数据 { ret = ModelUtils.InitializeAutomapper().Map<Student>(reader); } }
2. 启用AutoMapper DataReader扩展(推荐)
安装专门处理DataReader的AutoMapper扩展包:
dotnet add package AutoMapper.Data
修改ModelUtils中的映射配置,添加DataReader支持并验证配置有效性:
using AutoMapper; using AutoMapper.Data; using System.Data; namespace WebAPI.Models { public class ModelUtils { public static Mapper InitializeAutomapper() { var config = new MapperConfiguration(cfg => { cfg.AddDataReaderMapping(); // 启用DataReader映射支持 cfg.CreateMap<IDataReader, Student>(); // 使用IDataReader提升通用性 }); config.AssertConfigurationIsValid(); // 验证映射配置,提前发现错误 return new Mapper(config); } } }
3. 全局注册Mapper实例(最佳实践)
避免重复创建Mapper实例,在Program.cs中将AutoMapper注册为全局服务:
builder.Services.AddAutoMapper(cfg => { cfg.AddDataReaderMapping(); cfg.CreateMap<IDataReader, Student>(); }, typeof(Program));
修改Student类,通过依赖注入获取IMapper实例:
using System.Data; using System.Data.SqlClient; using AutoMapper; namespace WebAPI.Models { public class Student { private readonly IMapper _mapper; // 构造函数注入IMapper public Student(IMapper mapper) { _mapper = mapper; } public int StudentID { get; set; } public string StudentFirstName { get; set; } = string.Empty; public string StudentLastName { get; set; } = string.Empty; public async Task<Student> GetStudentByID(string conn, int studentID) { using (var connection = new SqlConnection(conn)) { var cmd = new SqlCommand("Core.StudentByID_Get", connection); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("StudentID", studentID); await connection.OpenAsync(); using (var reader = await cmd.ExecuteReaderAsync()) { if (await reader.ReadAsync()) { return _mapper.Map<Student>(reader); } } } return new Student(_mapper); // 返回空实例或根据需求处理 } } }
4. 处理命名不匹配的情况
如果数据库列名与实体属性名不一致(比如列名为Student_FirstName,属性为StudentFirstName),需要显式配置字段映射:
cfg.CreateMap<IDataReader, Student>() .ForMember(dest => dest.StudentFirstName, opt => opt.MapFrom(src => src["Student_FirstName"])) .ForMember(dest => dest.StudentLastName, opt => opt.MapFrom(src => src["Student_LastName"]));
内容的提问来源于stack exchange,提问作者Steve Olson
相关产品推荐
相关产品推荐

