使用AutoMapper映射SQLite通用数据返回空列表,映射失败求助
解决AutoMapper从SQLite DataReader映射到IEnumerable失败的问题
看起来你遇到的是AutoMapper处理IDataReader映射时的常见配置问题,我来帮你一步步排查:
1. 首先,启用AutoMapper的DataReader映射支持
这是最容易忽略的关键步骤!AutoMapper对IDataReader/IDataRecord的映射并非默认开启,必须在配置时明确添加扩展支持:
var cfg = new MapperConfiguration(cfg => { // 核心:启用DataReader映射扩展 cfg.AddDataReaderMapping(); // 你的实体映射配置 cfg.CreateMap<IDataRecord, Layout>() // 若数据库列名与实体属性名不匹配,明确指定映射关系 .ForMember(dest => dest.LayoutId, opt => opt.MapFrom(src => src["layout_id"])) .ForMember(dest => dest.LayoutName, opt => opt.MapFrom(src => src["layout_name"])); }); // 强烈建议添加这行,提前验证映射配置的正确性,避免运行时才发现错误 cfg.AssertConfigurationIsValid(); // 创建IMapper实例(推荐用实例化对象而非静态Mapper类,避免线程安全和初始化问题) var mapper = cfg.CreateMapper();
2. 替换静态Mapper.Map为实例化的IMapper
旧版静态Mapper类容易出现初始化不彻底、多线程冲突等问题,改用实例化的IMapper更稳定可靠:
修改你的执行函数:
// 将IMapper作为参数传入(或通过依赖注入容器注入) public static IEnumerable<T> ExecuteReaderCommand<T>(SQLiteConnection connection, SQLiteCommand command, IMapper mapper) { var result = Enumerable.Empty<T>(); try { connection.Open(); command.Connection = connection; // 务必用using包裹DataReader,确保资源及时释放 using (var reader = command.ExecuteReader()) { // 使用实例化的mapper完成映射 result = mapper.Map<IEnumerable<T>>(reader); } } catch (Exception ex) { _logger.Error(ex, "Can't execute {command}, with {connection}", command, connection); } finally { // 检查连接状态后再关闭,避免重复关闭引发异常 if (connection.State == ConnectionState.Open) { connection.Close(); } } // 额外提示:SQLite对TransactionScope的支持有限,若无需跨连接事务,建议移除该逻辑 // 若必须保留,需确保SQLite版本支持且连接字符串配置了Enlist=true return result; }
3. 排查映射匹配细节问题
如果仍报Unmapped错误,按以下步骤逐一验证:
- 列名与属性名匹配:调试时遍历
reader.GetName(i)查看返回的数据库列名,确保与ForMember中指定的名称一致(注意大小写,AutoMapper默认区分大小写)。 - 属性访问权限:
Layout类的属性必须是public修饰的,AutoMapper无法映射私有/保护属性。 - 可空类型处理:若数据库列允许为空,实体对应属性需设为可空类型(如
int?而非int),或在映射时添加空值处理逻辑。
4. 额外建议:简化事务逻辑
SQLite对TransactionScope的支持有诸多限制,如果你的操作不需要跨多个连接的事务,建议直接移除该部分代码,避免引入不必要的复杂度。
按以上步骤调整后,应该能解决映射失败的问题。如果还有疑问,可以通过cfg.AssertConfigurationIsValid()输出的错误信息,精准定位未映射的属性。
内容的提问来源于stack exchange,提问作者Paxsentry
相关产品推荐
相关产品推荐

