EF Core调用存储过程执行Post请求时出现System.InvalidOperationException:FromSql操作结果缺少必填列'EmpID'的问题求助
首先,咱们来定位你遇到的错误根源:
Exception : System.InvalidOperationException: The required column 'EmpID' was not present in the results of a 'FromSql' operation.
这个错误的核心原因是:你用了FromSqlRaw来执行插入型的存储过程,但EF Core的FromSqlRaw是为查询操作设计的——它期望存储过程返回的结果集能完整映射到EmployeeDetails实体,而你的存储过程只做了数据插入,没有返回任何包含EmpID的结果集。加上EmployeeDetails里的EmpID被标记为[Key],EF Core会强制要求结果集里必须有这个列,所以就抛出了错误。
接下来给你分步解决的方案:
1. 替换执行存储过程的方式(核心修复)
把执行插入存储过程的代码从FromSqlRaw改成ExecuteSqlRawAsync——这是EF Core专门用来执行非查询操作(插入、更新、删除)的方法,不会要求返回结果集映射到实体。
修改控制器里的这段代码:
// 原来错误的写法 await _context.EmployeeDetails.FromSqlRaw(StoredProc).ToListAsync(); // 改为正确的非查询执行方式 await _context.Database.ExecuteSqlRawAsync(StoredProc);
2. 修复SQL注入风险(重要优化)
你现在直接拼接字符串生成存储过程调用语句,存在严重的SQL注入风险。应该改用参数化的方式传递参数:
// 用参数化查询替换字符串拼接 var storedProc = "EXEC PROC_INSERTEMPLOYEEDETAILS @FirstName, @LastName, @Status, @Age, @Designation, @Salary, @DoorNo, @StreetName, @Area, @City, @State, @ContactNo, @EmailID, @Qualification, @Experience, @FormerCompany, @AwardsAndTitles"; await _context.Database.ExecuteSqlRawAsync( storedProc, new SqlParameter("@FirstName", id.FirstName), new SqlParameter("@LastName", id.LastName), new SqlParameter("@Status", id.Status), new SqlParameter("@Age", id.Age), new SqlParameter("@Designation", id.Designation), new SqlParameter("@Salary", id.Salary), new SqlParameter("@DoorNo", id.DoorNo), new SqlParameter("@StreetName", id.StreetName), new SqlParameter("@Area", id.Area), new SqlParameter("@City", id.City), new SqlParameter("@State", id.State), new SqlParameter("@ContactNo", id.ContactNo), new SqlParameter("@EmailID", id.EmailID), new SqlParameter("@Qualification", id.Qualification), new SqlParameter("@Experience", id.Experience), new SqlParameter("@FormerCompany", id.FormerCompany), new SqlParameter("@AwardsAndTitles", id.AwardsAndTitles) );
3. 修复存储过程的事务处理(可选但推荐)
你的存储过程CATCH块里的逻辑有问题:当XACT_STATE() = 1时,说明事务是可提交的,但如果已经进入CATCH块,说明发生了错误,应该回滚而不是提交。修正后的CATCH块:
BEGIN CATCH IF (XACT_STATE()) <> 0 BEGIN ROLLBACK TRANSACTION END SELECT 'Error' = @@ERROR END CATCH
4. 优化输入模型的EmpID定义
你的EmployeeDetails模型里EmpID是字段(没有get;set;),虽然标记了[JsonIgnore],但EF Core实体映射通常要求属性(带getter/setter),建议改成:
[Key] [JsonIgnore] public string EmpID { get; set; }
最终的控制器代码片段
修改后的GetEmployeeDetails1方法大概是这样:
[Route("AddEmployee")] [HttpPost] public async Task<ActionResult<IEnumerable<EmployeeDet>>> GetEmployeeDetails1([FromBody] EmployeeDetails id) { try { // 参数化存储过程调用 var storedProc = "EXEC PROC_INSERTEMPLOYEEDETAILS @FirstName, @LastName, @Status, @Age, @Designation, @Salary, @DoorNo, @StreetName, @Area, @City, @State, @ContactNo, @EmailID, @Qualification, @Experience, @FormerCompany, @AwardsAndTitles"; await _context.Database.ExecuteSqlRawAsync( storedProc, new SqlParameter("@FirstName", id.FirstName), new SqlParameter("@LastName", id.LastName), new SqlParameter("@Status", id.Status), new SqlParameter("@Age", id.Age), new SqlParameter("@Designation", id.Designation), new SqlParameter("@Salary", id.Salary), new SqlParameter("@DoorNo", id.DoorNo), new SqlParameter("@StreetName", id.StreetName), new SqlParameter("@Area", id.Area), new SqlParameter("@City", id.City), new SqlParameter("@State", id.State), new SqlParameter("@ContactNo", id.ContactNo), new SqlParameter("@EmailID", id.EmailID), new SqlParameter("@Qualification", id.Qualification), new SqlParameter("@Experience", id.Experience), new SqlParameter("@FormerCompany", id.FormerCompany), new SqlParameter("@AwardsAndTitles", id.AwardsAndTitles) ); // 查询最新插入的员工数据(修正原SQL的语法错误) return await _context.EmployeeDetails.FromSqlRaw("SELECT TOP 1 * FROM EmployeeDetails ORDER BY EmpID DESC").ToListAsync(); } catch(Exception ex) { return Ok("Exception : " + ex); } }
另外,注意你原代码里的查询语句Select Top 1 FROM EmployeeDetails有语法错误,少了*或者列名,已经修正为SELECT TOP 1 * FROM EmployeeDetails ORDER BY EmpID DESC。
按照这些步骤修改后,你的插入操作应该就能正常执行,不会再出现EmpID缺失的错误了。
内容的提问来源于stack exchange,提问作者Priyadharshini Charles

