【问题标题】:The required column was not present in the results of a 'FromSql' operation :. FromSqlInterpolated“FromSql”操作的结果中不存在所需的列:。 FromSqlInterpolated
【发布时间】:2020-07-02 21:24:29
【问题描述】:

[前导码]

当我将我的 api 从 .netcore2.1 升级到 .netcore3.1 时,我发现我需要大幅更改我的实体框架代码。

我没有意识到我的远程数据库中的存储过程中有一个错误,我的 .netcore2.1 代码中没有表达。

我遇到的错误消息并没有指出检查存储过程内部的方向。我留下我的问题的最终形式,以防搜索错误消息对某人有帮助。

[问题]

我有下面的代码调用一个返回整数的存储过程

代码在服务器端单元测试中工作,但在通过 api 或通过 SwaggerUI 调用时失败

var obj = connect.Ints.FromSqlInterpolated<intDto>(@$"Set NOCOUNT ON
          declare @num int 
          exec @num = spGetDefaultID {userName}  
          select @num as num").ToList();

id = (int)obj.First().num;

connect 是我的 DbContext 包含的位置

public DbSet<intDto> Ints { get; set; }  // I actually don't want a table

public class intDto
{
    public int num { get; set; }
}

我关注了the advice to create a dummy view,这样我的数据库中就不会出现不需要的表。

并且拥有

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<intDto>).HasNoKey().ToView("view_name_that_doesnt_exist");

调用栈是

System.InvalidOperationException: The required column 'num' was not present in the results of a 'FromSql' operation.
at Microsoft.EntityFrameworkCore.Query.Internal.BufferedDataReader.BufferedDataRecord.InitializeFields()
at Microsoft.EntityFrameworkCore.Query.Internal.BufferedDataReader.BufferedDataRecord.Initialize(DbDataReader reader, IReadOnlyList`1 columns)
at Microsoft.EntityFrameworkCore.Query.Internal.BufferedDataReader.Initialize(IReadOnlyList`1 columns) 
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.InitializeReader(DbContext _, Boolean result)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementation[TState,TResult](Func`3 operation, Func`3 verifySucceeded, TState state)
at Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)   
at MyAPi.Job_Management.JobDataRead.GetCartIdForUser(ApiDbContext connect, String userName) 

请注意,我已对这个问题进行了大量编辑,因为有一次我让 api 工作,但不再工作。

我发现我必须使用 .ToList() 否则会出错

System.InvalidOperationException:FromSqlRaw 或 FromSqlInterpolated 用不可组合的 SQL 和在其上组成的查询调用。 考虑在 FromSqlRaw 之后调用 AsEnumerable 或 FromSqlInterpolated 方法在客户端执行组合 一边。

[更新]

我弹出以下代码,它没有失败

 var obj = db.Ints.FromSqlInterpolated(@$"Set NOCOUNT on
                                       select count(*) as num from people 
                                       where email like  {name} ").ToList();

所以下一步是尝试创建一个新的存储过程

或者可能是数据库版本..

有趣的是,除非我有,否则单元测试会失败

Microsoft.EntityFrameworkCore.Relational.dll

在正在测试的项目中引用。即使我没有明确使用它。

这个场景的错误信息是

System.MissingMethodException: 'Method not found:'System.Linq.IQueriable '1<!!O> 
Microsoft.EntityFrameworkCore.RelationalQueryableExtensions.
FromSqlInterpolated(Microsoft.EntityFrameworkCOre.DbSet'1<!!0>, 
System.FormattableString)'

我尝试将代码更改为

var obj = connect.Ints.FromSqlInterpolated<intDto>(@$"declare @num int 
          exec @num = spGetDefaultID {userName}").ToList();

但是我的单元测试出错了

The underlying reader doesn't have as many fields as expected

[更新]

远程存储过程使用结果集返回数据。

create PROCEDURE [dbo].[spGetDefaultID] 
@email varchar(300)
AS
BEGIN
    SET NOCOUNT ON;
    declare @cartID int
    select @CartID= id from people where email = @email   /* simplified */
    select @CartID /* this line was not present in my local database */
    return @CartID  
END

【问题讨论】:

  • 公共整数?编号。 ???
  • 当您尝试直接在 SSMS 中运行 sql 代码时会发生什么?
  • 我并没有真正解决任何问题,只是为您指明了正确的方向。我认为您应该发布自己问题的答案。
  • 好的,我错过了最新的修订版 + 答案,因为该问题已在选项卡中打开了一段时间。不过,这个问题可以大大压缩,使其和答案更值得未来访问者阅读。
  • 一个随机添加的东西,您可以使用 EXEC 的 WITH RESULT SETS 部分来定义输出列及其名称。刚刚解决了我的 FromSql 问题。

标签: sql-server entity-framework-core autorest swashbuckle.aspnetcore


【解决方案1】:

当我尝试按照 Zohar 的建议使用 ssms 调用存储过程时,我惊讶地看到 2 个结果输出

当我删除了不必要的

选择@CartID

问题解决了。

【讨论】:

    【解决方案2】:

    1.你需要修改你的存储过程。您需要一个输出参数。它应该看起来。像这样:

    CREATE PROCEDURE [dbo].[spGetDefaultID] (
                     @Username VARCHAR(100)
                    ,@num_output int OUTPUT)
    AS 
    BEGIN
      SELECT @num_output = count(*)
      FROM [Person].[Person]
      WHERE PersonType LIKE (@Username)
    RETURN
    END
    

    2.您需要修改一行代码。语法与您选择的语法略有不同。您需要 OUTPUT 语句。

    SET NOCOUNT ON
    DECLARE @num INT
    exec spGetDefaultID {UserName}, @num_output=@num OUTPUT;
    SELECT @num AS num
    

    让您感到困惑的部分可能是 SQL 正在返回一个值,即使您像一开始那样编写它,但它没有将结果存储在 @num 参数中。

    我希望这能解决您的问题。 有关如何Return Data from a Stored Procedure 的更多信息,请参阅 Microsoft Docs。

    【讨论】:

    • 谢谢马蒂亚斯。我更新了问题以显示我正在通过结果集返回数据。
    猜你喜欢
    • 1970-01-01
    • 2019-07-20
    • 2019-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多