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
672   13  

13 ответов:

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

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

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

SET FMTONLY ON

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

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

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

добавление этого нелогического блока кода решило проблему. Даже если он никогда не ударит

IF 1=0 BEGIN
    SET FMTONLY OFF
END

Почему мой типизированный набор данных не похож на временные таблицы?

http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataset/thread/fe76d511-64a8-436d-9c16-6d09ecf436ea/

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

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 должен быть в состоянии распознать возвращаемый тип столбцов.

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

то, что я бы добавил:

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

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

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

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

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

(SET FMTONLY OFF никогда не работал для меня, поэтому я просто временно изменил свои SProcs, чтобы получить информацию о столбце, а не беспокоиться о взломе на стороне EF так же, как К ВАШЕМУ СВЕДЕНИЮ.)

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

оба решения : 1-Определите возвращенный сложный тип вручную (я думаю, он должен работать) 2-Используйте Хак и просто для добавления хранимой процедуры, поставленной в ее начале, установите 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

спасибо

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

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

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

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

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

SET FMTONLY OFF 

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

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

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

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

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

в Entity framework при получении информации о столбце sql выполняет процедуру с передачей нулевых значений в параметре. Поэтому я обрабатывал случай null по-разному, создавая временную таблицу со всеми необходимыми столбцами и возвращая все столбцы без значения, когда 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

Я не получал информацию о столбце моем случае после помощью командлета set FMTONLY от уловка.

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

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

Entity Framework попытается получить столбцы, выполнив хранимую процедуру, передавая NULL для каждого аргумента.

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

  2. ER делает следующее, Чтобы получить метаданные таблица:

    УСТАНОВИТЕ FMTONLY НА

  3. это нарушит вашу хранимую процедуру в различных обстоятельствах, в частности, если она использует временную таблицу.

  4. поэтому, чтобы получить результат в виде сложного типа; пожалуйста, попробуйте добавить

    SET FMTONLY OFF;

Это работает для меня - надеюсь, что это работает для вас тоже.

ссылка https://social.msdn.microsoft.com/Forums/en-US/e7f598a2-6827-4b27-a09d-aefe733b48e6/entity-model-add-function-import-stored-procedure-returns-no-columns?forum=adodotnetentityframework

Comments

    Ничего не найдено.