EF4 - la procédure stockée sélectionnée ne renvoie aucune colonne
j'ai requête dans une procédure stockée qui appelle certains serveurs liés avec un certain SQL dynamique. Je comprends que EF n'aime pas cela, donc j'ai spécifiquement énuméré toutes les colonnes qui seraient retournées. Pourtant, elle n'est pas toujours comme ça. Ce que je fais mal? Je veux juste que EF soit capable de détecter les colonnes retournées à partir de la procédure stockée pour que je puisse créer les classes dont j'ai besoin.
s'il vous Plaît voir le code suivant qui fait les dernières lignes de ma procédure stockée:
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
13 réponses
EF ne supporte pas l'importation de procédures stockées qui construisent un jeu de résultats à partir de:
- requêtes dynamiques
- tables temporaires
la raison est que pour importer la procédure EF doit l'exécuter . Une telle opération peut être dangereuse car elle peut déclencher certaines modifications dans la base de données. À cause de cela, EF utilise la commande spéciale SQL avant d'exécuter la procédure stockée.:
SET FMTONLY ON
en exécutant cette procédure stockée de commande retournera seulement des" métadonnées " au sujet des colonnes dans son ensemble de résultats et il n'exécutera pas sa logique. Mais parce que la logique n'a pas été exécutée il n'y a pas de table temporaire (ou de requête dynamique construite) donc les métadonnées ne contiennent rien.
vous avez deux choix (sauf celui qui nécessite de réécrire votre procédure stockée pour ne pas utiliser ces fonctionnalités):
- définit retourné le type complexe manuellement (je suppose que cela devrait fonctionner)
- utilisez un hack et juste pour ajouter la procédure stockée mis à son début
SET FMTONLY OFF
. Cela permettra au reste du code de votre SP de s'exécuter normalement. Assurez-vous simplement que votre SP ne modifie aucune donnée car ces modifications seront exécutées lors de l'importation! Après l'importation réussie supprimez ce piratage.
L'ajout de ce bloc de code Non logique a résolu le problème. Même s'il ne sera jamais atteint
IF 1=0 BEGIN
SET FMTONLY OFF
END
Pourquoi mon ensemble de données dactylographiées n'aime-t-il pas les tableaux temporaires?
ou vous pouvez créer un type de Table défini par L'Utilisateur et le retourner.
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
puis dans la procédure:
DECLARE @tempTable dbo.T1
INSERT @tempTable (ID, Field1, Field2, Field3)
SELECT .....
....
SELECT * FROM @tempTable
maintenant EF devrait être capable de reconnaître le type de colonnes retournées.
comme d'autres l'ont fait remarquer, assurez-vous que la procédure fonctionne réellement. En particulier, dans mon cas, J'exécutais la procédure heureusement sans erreur dans SQL Server Management Studio oubliant complètement que j'étais connecté avec des droits d'administration. Dès que j'ai essayé d'exécuter la procédure en utilisant l'utilisateur principal de mon application, j'ai trouvé qu'il y avait une table dans la requête que cet utilisateur n'avait pas la permission d'accéder.
ce que j'ajouterais est:
que l'importation échoue également si les procédures stockées ont des paramètres et ne renvoie aucun résultat défini pour les valeurs par défaut des paramètres.
ma procédure stockée avait 2 paramètres de flotteur et ne retournerait rien quand les deux paramètres sont 0.
afin d'ajouter cette procédure stockée pour le modèle d'entité, j'ai défini la valeur de ces paramètres dans la procédure stockée, de sorte qu'il est garanti à renvoie quelques lignes, quels que soient les paramètres.
ensuite, après avoir ajouté cette procédure stockée au modèle d'entité, je défais les changements.
note intéressante: avait le même problème que j'ai d'abord résolu en utilisant des Variables de Table, plutôt que des Tables de température (juste pour l'importation). Ce n'était pas particulièrement intuitif pour moi, et m'a mis à l'écart en observant initialement mes deux SProcs: l'un utilisant des tables de température et l'autre avec des Variables de Table.
(SET FMTONLY OFF n'a jamais fonctionné pour moi, donc j'ai juste changé mes SProcs temporairement pour obtenir les informations de la colonne, plutôt que de s'embêter avec le hack sur le côté EF tout comme un FYI.)
Ma meilleure option était vraiment juste créer manuellement le type complexe et la cartographie de la fonction Importer à elle. Fonctionnait bien, et la seule différence a fini par être qu'un FactoryMethod supplémentaire pour créer les propriétés a été inclus dans le concepteur.
les deux solutions : 1-Définir le type de complexe retourné manuellement (je suppose que cela devrait fonctionner) 2-Utilisez un hack et juste pour ajouter la procédure stockée mis à son début mis FMTONLY OFF.
ne pas travailler avec moi dans une procédure, mais il a travaillé avec l'autre!
ma procédure se termine par cette ligne:
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
Merci
en plus de ce que @tmanthley a dit, assurez-vous que votre procédure stockée fonctionne réellement en l'exécutant d'abord dans SSMS. J'avais importé quelques procédures stockées et oublié quelques fonctions scalaires dépendantes, ce qui a amené EF à déterminer que la procédure ne retournait pas de colonnes. On dirait une erreur que j'aurais dû attraper plus tôt, mais EF ne vous donne pas de message d'erreur dans ce cas.
dans mon cas ajouter SET NOCOUNT ON;
en haut de la procédure a résolu le problème. C'est la meilleure pratique de toute façon.
dans mon cas, SET FMTONLY OFF n'a pas fonctionné. La méthode que j'ai suivie est, j'ai pris la sauvegarde de la procédure stockée originale et remplacer par seulement le nom de la colonne comme la requête ci-dessous.
Select Convert(max,'') as Id,Convert(max,'') as Name
après ce changement, créer une nouvelle fonction d'importation, le type complexe dans le cadre d'entité. Une fois que la fonction import et le type complexe sont créés, remplacez la requête ci-dessus par votre procédure stockée originale.
SET FMTONLY OFF
a travaillé pour moi pour l'une des procédures mais a échoué pour les autres. Les étapes suivantes m'aident à résoudre mon problème
-
dans le cadre d'une procédure stockée, j'ai créé une table temporaire avec le même type de colonne et inséré toutes les données retournées par requête dynamique à la table temp. et sélectionné les données de la table de température.
Create table #temp ( -- columns with same types as dynamic query ) EXEC sp_executeSQL @sql insert into #temp Select * from #temp drop table #temp
-
supprimé type complexe existant, importation fonction et instance de procédure stockée pour l'ancienne procédure stockée et le modèle d'entité mis à jour pour la nouvelle procédure actuelle.
-
éditez la fonction importée dans entity modal pour le type complexe désiré, vous y obtiendrez toutes les informations de colonne qui n'est pas obtenu pour la procédure stockée précédente.
-
une fois que vous avez fait avec la création de type, vous pouvez supprimer la table temporaire de la procédure stockée et puis actualiser Entity Framework.
dans Entity framework, tout en obtenant des informations sur les colonnes, le sql exécute la procédure en passant des valeurs nulles dans le paramètre. Donc j'ai géré le cas null différemment en créant une table temp avec toutes les colonnes requises et en retournant toutes les colonnes avec aucune valeur quand null est passé à la procédure.
dans ma procédure il y avait requête dynamique, quelque chose comme
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
Je ne recevais pas les informations de la colonne dans mon cas après utiliser le jeu FMTONLY OFF trick.
c'est la table temporaire que j'ai créée pour obtenir les données Vierges. Maintenant je reçois la colonne info
Create table #UserPrfTemp
(
[USER_ID] bigint,
[FIRST_NAME] nvarchar(60),
SCHOOL_NAME nvarchar(60),
SOCIETY_NAME nvarchar(200)
.....
}
Entity Framework va essayer d'obtenir les colonnes en exécutant votre procédure stockée, en passant NULL pour chaque argument.
-
S'il vous plaît assurez-vous que la procédure stockée retournera quelque chose dans toutes les circonstances. Note qu'il aurait été plus intelligent d'Entity Framework pour exécuter la procédure stockée avec des valeurs par défaut pour les arguments, par opposition à des valeurs Null.
-
ER fait ce qui suit pour obtenir le métadonnées de la table:
SET FMTONLY ON
-
cela cassera votre procédure stockée dans diverses circonstances, en particulier, si elle utilise une table temporaire.
-
ainsi pour obtenir un résultat en tant que type complexe; s'il vous plaît essayer en ajoutant
SET FMTONLY OFF;
Cela a fonctionné pour moi - espérons que cela fonctionne pour vous aussi.