'FromSql' 操作的结果中不存在所需的列:。 FromSqlInterpolated
The required column was not present in the results of a 'FromSql' operation :. FromSqlInterpolated
[前言]
当我将 api 从 .netcore2.1 升级到 .netcore3.1 时,我发现我需要大幅更改我的 Entity Framework 代码。
我没有意识到的是,我的远程数据库中的存储过程中存在错误,我的 .netcore2.1 代码中没有表达该错误。
我遇到的错误消息并没有指出我在存储过程内部进行检查的方向。我留下问题的最终形式,以防搜索错误消息对某人有所帮助。
[问题]
我有以下代码来调用存储过程 returns 一个整数
该代码在服务器端单元测试中有效,但在通过 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; }
}
我关注了 这样我就不会在我的数据库中得到不需要的 table。
并且有
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 or FromSqlInterpolated
was called with non-composable SQL and with a query composing over it.
Consider calling AsEnumerable
after the FromSqlRaw or
FromSqlInterpolated method to perform the composition on the client
side.
[更新]
我输入了以下代码,它没有失败
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
[更新]
远程存储过程returns数据使用结果集。
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
1.You 需要修改您的存储过程。您需要一个输出参数。它应该看起来……像这样:
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.You 需要修改一行代码。语法与您选择的略有不同。您需要 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。
当我按照 Zohar 的建议尝试使用 ssms 调用存储过程时,我惊讶地看到了 2 个结果输出
当我删除不需要的
select @CartID
问题已解决。
[前言]
当我将 api 从 .netcore2.1 升级到 .netcore3.1 时,我发现我需要大幅更改我的 Entity Framework 代码。
我没有意识到的是,我的远程数据库中的存储过程中存在错误,我的 .netcore2.1 代码中没有表达该错误。
我遇到的错误消息并没有指出我在存储过程内部进行检查的方向。我留下问题的最终形式,以防搜索错误消息对某人有所帮助。
[问题]
我有以下代码来调用存储过程 returns 一个整数
该代码在服务器端单元测试中有效,但在通过 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; }
}
我关注了
并且有
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 or FromSqlInterpolated was called with non-composable SQL and with a query composing over it. Consider calling
AsEnumerable
after the FromSqlRaw or FromSqlInterpolated method to perform the composition on the client side.
[更新]
我输入了以下代码,它没有失败
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
[更新]
远程存储过程returns数据使用结果集。
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
1.You 需要修改您的存储过程。您需要一个输出参数。它应该看起来……像这样:
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.You 需要修改一行代码。语法与您选择的略有不同。您需要 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。
当我按照 Zohar 的建议尝试使用 ssms 调用存储过程时,我惊讶地看到了 2 个结果输出
当我删除不需要的
select @CartID
问题已解决。