Подтвердить что ты не робот

EF4 - выбранная хранимая процедура не возвращает столбцы

У меня есть запрос в хранимой процедуре, которая вызывает некоторые связанные серверы с некоторым динамическим SQL. Я понимаю, что EF этого не нравится, поэтому я специально перечислил все столбцы, которые будут возвращены. Тем не менее, это все еще не нравится. Что я здесь делаю неправильно? Я просто хочу, чтобы EF смог обнаружить столбцы, возвращаемые из хранимой процедуры, чтобы я мог создавать классы, которые мне нужны.

См. следующий код, который составляет последние строки моей хранимой процедуры:

SELECT
    #TempMain.ID,
    #TempMain.Class_Data,
    #TempMain.Web_Store_Class1,
    #TempMain.Web_Store_Class2,
    #TempMain.Web_Store_Status,
    #TempMain.Cur_1pc_Cat51_Price,
    #TempMain.Cur_1pc_Cat52_Price,
    #TempMain.Cur_1pc_Cat61_Price,
    #TempMain.Cur_1pc_Cat62_Price,
    #TempMain.Cur_1pc_Cat63_Price,
    #TempMain.Flat_Length,
    #TempMain.Flat_Width,
    #TempMain.Item_Height,
    #TempMain.Item_Weight,
    #TempMain.Um,
    #TempMain.Lead_Time_Code,
    #TempMain.Wp_Image_Nme,
    #TempMain.Wp_Mod_Dte,
    #TempMain.Catalog_Price_Chg_Dt,
    #TempMain.Description,
    #TempMain.Supersede_Ctl,
    #TempMain.Supersede_Pn,
    TempDesc.Cust_Desc,
    TempMfgr.Mfgr_Item_Nbr,
    TempMfgr.Mfgr_Name,
    TempMfgr.Vendor_ID
FROM
    #TempMain
        LEFT JOIN TempDesc ON #TempMain.ID = TempDesc.ID
        LEFT JOIN TempMfgr ON #TempMain.ID = TempMfgr.ID
4b9b3361

Ответ 1

EF не поддерживает импорт хранимых процедур, которые строят результирующий набор из:

  • Динамические запросы
  • Временные таблицы

Причина в том, что для импорта процедуры EF должен выполнить ее. Такая операция может быть опасной, поскольку она может вызвать некоторые изменения в базе данных. Из-за этого EF использует специальную команду SQL перед выполнением хранимой процедуры:

SET FMTONLY ON

Выполняя эту команду, хранимая процедура возвращает только "метаданные" о столбцах в своем результирующем наборе и не выполняет свою логику. Но поскольку логика не была выполнена, нет временной таблицы (или встроенного динамического запроса), поэтому метаданные не содержат ничего.

У вас есть два варианта (кроме тех, которые требуют повторной записи вашей хранимой процедуры, чтобы не использовать эти функции):

  • Определить возвращаемый сложный тип вручную (я думаю, он должен работать)
  • Используйте взломать и просто для добавления хранимой процедуры, поставленной в начале SET FMTONLY OFF. Это позволит выполнить остальную часть вашего кода SP обычным способом. Просто убедитесь, что ваш SP не изменяет никаких данных, поскольку эти изменения будут выполняться во время импорта! После успешного импорта удалите этот хак.

Ответ 3

Или вы можете создать пользовательский тип таблицы и вернуть это.

CREATE TYPE T1 AS TABLE 
( ID bigint NOT NULL
  ,Field1 varchar(max) COLLATE Latin1_General_CI_AI NOT NULL
  ,Field2 bit NOT NULL
  ,Field3 varchar(500) NOT NULL
  );
GO

Тогда в процедуре:

DECLARE @tempTable dbo.T1

INSERT @tempTable (ID, Field1, Field2, Field3)
SELECT .....

....

SELECT * FROM @tempTable

Теперь EF должен распознавать тип возвращаемых столбцов.

Ответ 4

Как отмечали некоторые другие, убедитесь, что процедура действительно выполняется. В частности, в моем случае я успешно выполнял эту процедуру без ошибок в SQL Server Management Studio, полностью забывая, что я вошел в систему с правами администратора. Как только я попробовал запустить процедуру, используя моего главного пользователя приложения, я обнаружил, что в запросе была таблица, в которой у этого пользователя нет доступа для доступа.

Ответ 5

Я бы добавил:

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

У моей хранимой процедуры было два параметра float и ничего не возвращал, когда оба параметра равны 0.

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

Затем после добавления этой хранимой процедуры в модель сущности я отключил изменения.

Ответ 6

Интересная сторона примечания: имела ту же проблему, которую я сначала решил, используя Табличные переменные, а не таблицы Temp (только для импорта). Это не было особенно интуитивно для меня и отбросило меня, когда первоначально наблюдали мои два SProcs: один использовал таблицы Temp и один с Table Variables.

(SET FMTONLY OFF никогда не работал у меня, поэтому я просто временно изменил свои SProcs, чтобы получить информацию о столбце, вместо того, чтобы беспокоиться о взломе на стороне EF так же, как FYI.)

Мой лучший вариант - это просто ручное создание сложного типа и отображение импорта функции в него. Работала отлично, и единственное отличие в том, что в Designer был добавлен дополнительный FactoryMethod для создания свойств.

Ответ 7

оба решения: 1- Определите возвращаемый сложный тип вручную (я думаю, он должен работать) 2. Используйте хак и просто для добавления хранимой процедуры, установленной в начале SET FMTONLY OFF.

не работал со мной в какой-то процедуре, однако он работал с другим!

моя процедура заканчивается этой строкой:

SELECT machineId, production [AProduction]
        , (select production FROM #ShiftBFinalProd WHERE machineId = #ShiftAFinalProd.machineId) [BProduction]
        , (select production FROM #ShiftCFinalProd WHERE machineId = #ShiftAFinalProd.machineId) [CProduction]
     FROM #ShiftAFinalProd
     ORDER BY machineId

Спасибо

Ответ 8

В дополнение к тому, что сказал @tmanthley, убедитесь, что ваша хранимая процедура фактически работает, запустив ее сначала в SSMS. Я импортировал некоторые хранимые процедуры и забыл о нескольких зависимых скалярных функциях, что заставило EF определить, что процедура не вернула столбцы. Похоже на ошибку, которую я должен был поймать раньше, но EF не дает вам сообщения об ошибке в этом случае.

Ответ 9

В моем случае добавление SET NOCOUNT ON; в верхней части процедуры устранило проблему. В любом случае, это лучшая практика.

Ответ 10

В моем случае SET FMTONLY OFF не работает. Следующим методом я взял резервную копию оригинальной хранимой процедуры и заменил ее только именем столбца, подобным приведенному ниже запросу.

Select Convert(max,'') as Id,Convert(max,'') as Name

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

Ответ 11

SET FMTONLY OFF 

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

  • В хранимой процедуре я создал временную таблицу с тем же типом столбца и вставил все данные, возвращаемые динамическим запросом в таблицу temp. и выбрали данные таблицы temp.

    Create table #temp
    (
       -- columns with same types as dynamic query    
    )
    
    EXEC sp_executeSQL @sql 
    
    insert into #temp 
        Select * from #temp 
    
    drop table #temp
    
  • Удаленный существующий сложный тип, функция импорта и экземпляр хранимой процедуры для старой хранимой процедуры и обновленная модель сущности для текущей новой процедуры.

  • Отредактируйте импортированную функцию в сущности модальной для желаемого сложного типа, вы получите всю информацию о столбцах, которая не получает для предыдущей хранимой процедуры.

  • Как только вы закончите создание типа, вы можете удалить временную таблицу из хранимой процедуры, а затем обновить Entity Framework.

Ответ 12

В структуре Entity при получении информации о столбцах sql выполняет процедуру с передачей нулевых значений в параметре. Поэтому я обработал нулевой случай по-другому, создав временную таблицу со всеми необходимыми столбцами и возвращая все столбцы без значения, когда null передается процедуре.

В моей процедуре был динамический запрос, что-то вроде

declare @category_id    int
set @category_id = (SELECT CATEGORY_ID FROM CORE_USER where USER_ID = @USER_ID)
declare @tableName varchar(15)
declare @sql VARCHAR(max)     
declare  @USER_IDT  varchar(100)    
declare @SESSION_IDT  varchar(10)

 IF (@category_id = 3)     
set @tableName =  'STUD_STUDENT'
else if(@category_id = 4)
set @tableName = 'STUD_GUARDIAN'


if isnull(@tableName,'')<>'' 
begin

set @sql  = 'SELECT  [USER_ID], [FIRST_NAME], SCHOOL_NAME, SOCIETY_NAME, SCHOOL_ID,
SESSION_ID, [START_DATE], [END_DATE]
from  @tableName
....
EXECUTE   (@sql)
END

ELSE
BEGIN
SELECT  * from #UserPrfTemp
END

Я не получал информацию о столбце в  мой случай после использования установленного FMTONLY OFF трюка.

Это временная таблица, которую я создал для получения пустых данных. Теперь я получаю информацию о колонке

Create table #UserPrfTemp
(
[USER_ID] bigint, 
[FIRST_NAME] nvarchar(60),
SCHOOL_NAME nvarchar(60),
SOCIETY_NAME nvarchar(200)
.....
}