Entity Framework绑定错误:适配含额外SQL列的两个Razor页面
解决Entity Framework与共用Razor绑定类的列匹配问题
这个问题其实很典型——EF的FromSql会严格匹配实体类的属性和查询结果的列,页面1的查询没返回Rsp,但实体类里加了这个属性,EF自然就找不到对应的列报错了。给你几个实用的解决方案,按推荐程度排序:
方案1:拆分实体类(最推荐,符合单一职责)
既然两个页面的查询返回的字段不一样,完全可以基于原有实体类做拆分:
- 先定义一个基类,包含
tblTime表的所有原有列:
public class tblTimeBase { // 这里放原有表的所有列属性,比如: public int Id { get; set; } public DateTime RecordTime { get; set; } // ...其他原有列 }
- 再创建一个继承自基类的子类,添加
Rsp属性:
public class tblTimeWithRsp : tblTimeBase { public string Rsp { get; set; } // 这里不需要virtual也能映射到查询的列,除非你需要动态代理的其他特性 }
- 页面1用
tblTimeBase作为绑定类,查询时返回基类:
result = await _context.Set<tblTimeBase>().FromSql("SELECT * FROM tblTime").ToListAsync();
(注意:如果tblTimeBase未在DbContext中注册为DbSet,就用Set<tblTimeBase>()来发起查询)
- 页面2用
tblTimeWithRsp作为绑定类,查询返回子类:
result = await _context.Set<tblTimeWithRsp>().FromSql("SELECT *, '自定义值' AS Rsp FROM tblTime").ToListAsync();
这种方式最清晰,每个类对应自己的查询结果,不会有冲突,后续扩展也更方便。
方案2:修改页面1的查询,补全Rsp列
如果不想拆分类,最简单的办法就是让页面1的查询也返回Rsp列,哪怕是NULL值:
// 页面1的查询修改为 result = await _context.tblTime.FromSql("SELECT *, NULL AS Rsp FROM tblTime").ToListAsync();
这样查询结果里就有Rsp列了,EF能匹配到实体类的属性,页面1不会报错,页面2的查询本来就有Rsp,也能正常工作。这个方案适合快速解决问题,但如果后续实体类加更多自定义列,每次都要修改查询,扩展性差一点。
方案3:使用[NotMapped]结合手动映射(不推荐,偏hack)
如果你一定要共用同一个实体类,可以试试用[NotMapped]标记Rsp,然后在页面2查询时手动映射,但这样需要额外的处理:
- 实体类里给
Rsp加[NotMapped]:
public class tblTime { // 原有列属性... [NotMapped] public string Rsp { get; set; } }
- 页面1的查询正常用
SELECT *,因为Rsp被标记为不映射,EF不会去匹配列,所以不会报错。 - 页面2的查询需要用匿名类型接收,再手动映射到实体类:
// 用ADO.NET辅助查询更可靠 var connection = _context.Database.GetDbConnection(); await connection.OpenAsync(); using var command = connection.CreateCommand(); command.CommandText = "SELECT *, '自定义值' AS Rsp FROM tblTime"; using var reader = await command.ExecuteReaderAsync(); var result = new List<tblTime>(); while (reader.Read()) { var item = new tblTime { // 手动赋值原有列,比如: Id = reader.GetInt32(reader.GetOrdinal("Id")), RecordTime = reader.GetDateTime(reader.GetOrdinal("RecordTime")), // ...其他列 Rsp = reader.IsDBNull(reader.GetOrdinal("Rsp")) ? null : reader.GetString(reader.GetOrdinal("Rsp")) }; result.Add(item); }
这个方案比较绕,而且容易出问题,不推荐作为长期方案。
总结一下,最推荐的还是方案1,拆分类让每个类对应自己的查询场景,代码更清晰也更容易维护。
内容的提问来源于stack exchange,提问作者Thomas Adrian
相关产品推荐
相关产品推荐

