Несовместимое исключение для чтения данных из сопоставленных объектов EF

Я использую работу с фреймом сущности и обновил таблицу и ее хранимую процедуру, но получаю следующую ошибку при вызове хранимой процедуры.

Считыватель данных несовместим с указанным "FormValueModel.Valuation". Элемент типа "ValuationId" не имеет соответствующего столбца в считывателе данных с тем же именем.

ValuationId - это мой первичный ключ, который я хочу автоматически увеличивать.

Я могу выполнить поиск хранимой процедуры из студии управления SQL, и когда я запускаю свое приложение, оно записывает в базу данных, но затем появляется сообщение об ошибке.

Я не знаком с фреймворком сущностей и имею только основы, и я думаю, что это может быть проблема с отображением из model.edmx.

Какова будет правильная процедура при воссоздании и отображении таблиц и хранимых процедур в модели?


Хранимая процедура.

    ALTER PROCEDURE [dbo].[ValuationCreate]
    @TrackingNumber varchar(100),
    @FormMobiValuationId varchar(100),
    @ValuationPropertyId int,
    @ValuationFileName varchar(50)

AS   

SET NOCOUNT ON
SET XACT_ABORT ON


DECLARE @ErrorMessage varchar(1000)



BEGIN TRANSACTION


    --Insert to Valuation
    INSERT INTO [Valuation]
    (
        TrackingNumber,
        FormMobiValuationId,
        ValuationPropertyId, -- new
        ValuationFileName,
        Date,
        ValuationStatus,
        IsActive
    )
    VALUES
    (
        @TrackingNumber,
        @FormMobiValuationId,
        @ValuationPropertyId,--new
        @ValuationFileName,
        GETDATE(),
        1, --Created
        1
    )





IF @@ERROR > 0
BEGIN
    SET @ErrorMessage = 'Valuation Insert failed'
    GOTO ErrorHandler
END
ELSE
BEGIN
    COMMIT TRANSACTION
    RETURN
END



ErrorHandler:

RAISERROR(@ErrorMessage,16,1);
ROLLBACK TRANSACTION
RETURN -1

C# вызов, где происходит ошибка, сообщение об ошибке появляется в последней строке.

 public ObjectResult<Valuation> ValuationCreate(global::System.String trackingNumber, global::System.String formMobiValuationId, Nullable<global::System.Int32> valuationPropertyId, global::System.String valuationFileName)
        {
            ObjectParameter trackingNumberParameter;
            if (trackingNumber != null)
            {
                trackingNumberParameter = new ObjectParameter("TrackingNumber", trackingNumber);
            }
            else
            {
                trackingNumberParameter = new ObjectParameter("TrackingNumber", typeof(global::System.String));
            }

            ObjectParameter formMobiValuationIdParameter;
            if (formMobiValuationId != null)
            {
                formMobiValuationIdParameter = new ObjectParameter("FormMobiValuationId", formMobiValuationId);
            }
            else
            {
                formMobiValuationIdParameter = new ObjectParameter("FormMobiValuationId", typeof(global::System.String));
            }

            ObjectParameter valuationPropertyIdParameter;
            if (valuationPropertyId.HasValue)
            {
                valuationPropertyIdParameter = new ObjectParameter("ValuationPropertyId", valuationPropertyId);
            }
            else
            {
                valuationPropertyIdParameter = new ObjectParameter("ValuationPropertyId", typeof(global::System.Int32));
            }

            ObjectParameter valuationFileNameParameter;
            if (valuationFileName != null)
            {
                valuationFileNameParameter = new ObjectParameter("ValuationFileName", valuationFileName);
            }
            else
            {
                valuationFileNameParameter = new ObjectParameter("ValuationFileName", typeof(global::System.String));
            }

            return base.ExecuteFunction<Valuation>("ValuationCreate", trackingNumberParameter, formMobiValuationIdParameter, valuationPropertyIdParameter, valuationFileNameParameter);
        }

12 ответов

Сообщение означает, что результаты хранимой процедуры не содержат столбец с именем ValudationId, Дважды проверьте ваш select и запустите его в SSMS, чтобы убедиться, что вы возвращаете этот столбец.

РЕДАКТИРОВАТЬ: Ваша процедура не содержит select заявление. Вам нужно выбрать вставленное значение идентичности (используя scope_identity() например), чтобы EF мог сопоставить его с сущностью.

Например,

insert into Table
(
    Col1,
    Col2
)
values
(
    1,
    2
)

select scope_identity() as IdentityColName

Кроме того, кроме того, вам не нужен весь этот бизнес транзакций в вашем операторе вставки; у вас есть только один оператор (ваша вставка), который изменяет данные.

Для тех, кто все еще получает ту же ошибку, убедитесь, что вы указываете / подключены к правильной базе данных. Потратив часы, я обнаружил, что работаю с активной базой данных, а не с тестовой. И, конечно, изменения, которые я внес в хранимую процедуру в тестовой базе данных, не имели эквивалента в активной базе данных.

В моем случае он возвращал данные, но имя столбца, не предоставленное, из-за CAST оператор, который не имеет псевдонима столбца, стал пустым. Ошибка имени отсутствующего столбца закончилась генерацией сообщения об ошибке сопоставления EF.

Сделав реальный вызов в SSMS и просмотрев результат, этот реальный результат показал эту очевидную ошибку:

введите описание изображения здесь

Присвоение имени столбцу в SQL того, что ожидал EF, решило проблему.

Avinash, хороший вызов на ExecuteSQLCommand и "не-запрос". Тем не менее, Pornster ссылается на ExecuteFunction, чтобы вызвать SP и вернуть результаты. Чтобы решить эту проблему, удалите оператор возврата из вашего SP, и он будет работать. Когда вы используете оператор return, SP будет возвращать int, а не ваш запрос select.

Странно, я решил это, добавив команду GO в конец хранимой процедуры.

Я исправил свою версию этой проблемы, просматривая Модель в VS, находя Сохраненный Процесс в разделе Импорт функций и меняя тип возвращаемого значения функции на Нет

Если вы вставляете / удаляете / обновляете (они рассматриваются EF как "незапрашиваемые") и могут быть вызваны нашим кодом с помощью

context.Database.ExecuteSqlCommand(insert into Table (Col1,Col2) values (1,2));

Но если вы делаете запрос select для необработанного оператора SQL, используйте

context.DbSet<Table_name>.SqlQuery(select * from table_name).ToList();

или context.Database.SqlQuery(выберите * из имени таблицы).ToList();

Функция SqlQuery() в EF по странным причинам вызывает исключение операции вставки / удаления / обновления. (Выдается исключение "Член типа, у которого нет соответствующего столбца в считывателе данных с тем же именем.") Но он фактически выполнил операцию, если вы откроете свою Sql Management Studio и проверите записи.

Также следите за случаями, когда файл EDMX вашей модели сопоставляет имя столбца базы данных с чем-то отличным от соответствующего объекта класса.

В моем случае хранимая процедура возвращала столбцы с пробелами в именах [Monthly Bill Rate], Чтобы справиться с этим, имя столбца было переназначено в модели.

В какой-то момент столбец возврата SP был переименован в [MonthlyBillRate], но модель не была обновлена, чтобы соответствовать. Когда я искал код для MonthlyBillRateтам это было в Designer.cs подать как MonthlyBillRate, Я не мог понять, почему я получил исключение. При ближайшем рассмотрении я нашел переназначенное имя в EDMX.

Model.edmx

Перераспределение происходит в ScalarProperty тег через ColumnName приписывать.

 <FunctionImportMapping FunctionImportName="BillingReport" FunctionName="Model.Store.BillingReport">
  <ResultMapping>
    <ComplexTypeMapping TypeName="Model.BillData">
      <ScalarProperty Name="MonthlyBillRate" ColumnName="Monthly Bill Rate" />
    </ComplexTypeMapping>
  </ResultMapping>

Model.Designer.cs

    [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
    [DataMemberAttribute()]
    public Nullable<global::System.Decimal> MonthlyBillRate
    {
      ... etc ...
    }

В моем случае, как предположил Бретт Джонс, решение состояло в том, чтобы удалить инструкцию "RETURN" из моей хранимой процедуры, оставив только часть "SELECT". Я часами пробую всевозможные решения, которые я нашел в Интернете, но это было так просто.

Одним из важных сценариев является получение разных результатов при разных условиях. Например, когда вы используете IF-команду, возможно, возвращать разные результаты из каждой ветви. Поскольку EF устанавливает возвращаемую коллекцию при импорте SP, ожидайте коллекцию [type one], но получите коллекцию [type 2], а затем вызовите ошибку, если в считывателе данных нет соответствующего столбца. Таким образом, любой SP с возвращаемым набором результатов должен возвращать одну и ту же коллекцию (как имя столбца и количество) из каждой части на нем, как показано ниже:

IF (Condition 1)
BEGIN
  SELECT [column1], [column2], [column3], ... FROM [...]
END
ELSE
BEGIN
  SELECT [column1], [column2], [column3], ... FROM [...]
END

Это работает для меня в том же вопросе и надеюсь быть полезным.

Обновить:

В другой раз я получил это сообщение об ошибке, когда у меня был неправильный тип коллекции возврата в Function Imports, На самом деле я не ожидал типизированных или некоторых значений коллекции и, возможно, мне просто нужно целое число как выходной параметр, но я забыл установить Returns a Collection Of в None, Так что, если вы не ожидаете какого-либо результата возврата, перейдите к вашей модели и в Model Browser > Function Imports сделать правый клик на SP есть проблемы и нажать Edit, затем проверить Returns a Collection Of раздел и установите его None,

Это не применимо к данному конкретному случаю, но у меня была похожая проблема, в которой была выдана та же ошибка, но указанный тип элемента был столбцом в моем выбранном столбце, исправленном с 1.... это из-за того, что я возвращал то же самое столбец дважды в моем выборе.... пример:-

SELECT
    CustomerId,
    FirstName,
    LastName,
    CustomerId
FROM
    Customers

ОСТЕРЕГАЙТЕСЬ "select *" в конце ваших хранимых процедур! Только руины лежат на этом темном пути.

Может быть, вы используете select без указания псевдонима столбца.

Другие вопросы по тегам