Требуемый столбец отсутствовал в результатах операции FromSql:. FromSqlInterpolated
[Pre-Amble]
Когда я обновил свой api с.netcore2.1 до.netcore3.1, я обнаружил, что мне нужно значительно изменить код Entity Framework.
Чего я не понимал, так это того, что у меня была ошибка в хранимой процедуре в моей удаленной базе данных, которая не выражалась в моем коде.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; }
}
Я последовал совету создать фиктивное представление, чтобы в базе данных не появлялась ненужная таблица.
и имеют
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 и с запросом, составляющим его. Рассмотрите возможность звонка
AsEnumerable
после метода FromSqlRaw или 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
2 ответа
Когда я попытался вызвать хранимую процедуру с помощью ssms, как было предложено Zohar, я был подавлен, чтобы увидеть 2 вывода результатов
Когда я удалил ненужное
выберите @CartID
проблема была решена.
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.
Надеюсь, это решит вашу проблему. Дополнительную информацию о том, как вернуть данные из хранимой процедуры, можно найти в Microsoft Docs.