web-dev-qa-db-fra.com

EF4 - La procédure stockée sélectionnée ne renvoie aucune colonne.

J'ai une requête dans une procédure stockée qui appelle des serveurs liés avec du SQL dynamique. Je comprends que EF n’aime pas cela, aussi j’ai énuméré précisément toutes les colonnes qui seraient retournées. Pourtant, il n'aime toujours pas ça. Qu'est-ce que je fais mal ici? Je veux juste que EF soit capable de détecter les colonnes renvoyées par la procédure stockée afin de pouvoir créer les classes dont j'ai besoin.

Veuillez consulter le code suivant qui constitue 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
59
cjbarth

EF ne prend pas en charge l’importation de procédures stockées qui construisent un ensemble de résultats à partir de:

  • Requêtes dynamiques
  • Tables temporaires

La raison en est que pour importer la procédure EF doit l'exécuter . Une telle opération peut être dangereuse car elle peut entraîner des modifications dans la base de données. A cause de cela, EF utilise une commande SQL spéciale avant d'exécuter la procédure stockée:

SET FMTONLY ON

En exécutant cette commande, la procédure stockée ne renverra que des "métadonnées" sur les colonnes de son jeu de résultats et n'exécutera pas sa logique. Mais comme la logique n'a pas été exécutée, il n'y a pas de table temporaire (ni 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 le type complexe retourné manuellement (je suppose que cela devrait fonctionner)
  • Utilisez un hack et juste pour ajouter la procédure stockée mise à 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 une importation réussie, supprimez ce hack.
140
Ladislav Mrnka

L'ajout de ce bloc de code non logique a résolu le problème. Même s'il ne sera jamais touché

IF 1=0 BEGIN
    SET FMTONLY OFF
END

Pourquoi mon jeu de données typé ne ressemble-t-il pas aux tables temporaires?

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

25

Ou vous pouvez créer un type de table défini par l'utilisateur et le renvoyer.

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 pouvoir reconnaître le type de colonne renvoyé.

12
Mauricio Ramalho

Comme d'autres l'ont noté, assurez-vous que la procédure est en cours d'exécution. En particulier, dans mon cas, j’exécutais heureusement la procédure sans erreur dans SQL Server Management Studio en oubliant complètement que j’étais connecté avec des droits d’administrateur. Dès que j'ai essayé d'exécuter la procédure en utilisant le principal utilisateur de mon application, j'ai découvert qu'il y avait une table dans la requête à laquelle cet utilisateur n'avait pas la permission d'accéder.

2
Chris Matthews

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é des procédures stockées et oublié quelques fonctions scalaires dépendantes, ce qui a amené EF à déterminer que la procédure ne renvoyait aucune colonne. Cela semble être une erreur que j'aurais du me tromper plus tôt, mais EF ne vous envoie pas de message d'erreur dans ce cas.

1
Derreck Dean

Ce que je voudrais ajouter est:

Le fait que l'importation échoue également si les procédures stockées ont des paramètres et ne renvoie aucun résultat pour les valeurs de paramètre par défaut.

Ma procédure stockée avait 2 paramètres float et ne renverrait rien lorsque les deux paramètres sont à 0.

Ainsi, afin d’ajouter cette procédure stockée au modèle d’entité, j’ai défini la valeur de ces paramètres dans la procédure stockée afin qu’elle puisse renvoyer certaines lignes, quels que soient les paramètres.

Ensuite, après avoir ajouté cette procédure stockée au modèle d'entité, j'ai annulé les modifications.

1
tmanthey

les deux solutions: 1- Définissez le type complexe renvoyé manuellement (je suppose que cela devrait fonctionner) 2- Utilisez un hack et ajoutez simplement la procédure stockée mise à son début SET FMTONLY OFF.

ne travaille pas avec moi dans une procédure mais cela a fonctionné avec une 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

1
Ahmed Mostafa

Note latérale 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 temporaires (juste pour l'importation). Cela n’était pas particulièrement intuitif pour moi, et j’ai eu du mal à observer mes deux SProcs: un avec des tables Temp et un avec des variables de table. 

(SET FMTONLY OFF n'a jamais fonctionné pour moi, alors je viens de modifier temporairement mes SProcs pour obtenir les informations sur la colonne, plutôt que de me soucier du hack du côté EF, comme si c'était une info.

Ma meilleure option consistait simplement à créer manuellement le type complexe et à y mapper l'importation de la fonction. Très bien fonctionné, et la seule différence était qu’une autre méthode FactoryMethod permettant de créer les propriétés était incluse dans le concepteur. 

1
user1076406
SET FMTONLY OFF 

a travaillé pour moi pour l'une des procédures mais a échoué pour une autre procédure. Suivre les étapes m'aide à résoudre mon problème

  1. Dans 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 renvoyées par une requête dynamique dans la table temporaire . Et sélectionné les données de la table temporaire. 

    Create table #temp
    (
       -- columns with same types as dynamic query    
    )
    
    EXEC sp_executeSQL @sql 
    
    insert into #temp 
        Select * from #temp 
    
    drop table #temp
    
  2. Suppression du type complexe existant, de la fonction d'importation et de l'instance de procédure stockée pour l'ancienne procédure stockée et du modèle d'entité mis à jour pour la nouvelle procédure actuelle.

  3. Editez la fonction importée en mode modal pour le type complexe souhaité, vous obtiendrez toutes les informations de colonne qui ne sont pas obtenues pour la procédure stockée précédente.

  4. une fois la création de type terminée, vous pouvez supprimer la table temporaire de la procédure stockée, puis actualiser Entity Framework.

0
PVIJAY

Dans Entity Framework, lors de l'obtention des informations sur les colonnes, SQL exécute la procédure en transmettant des valeurs null en paramètre. J'ai donc traité différemment la casse null en créant une table temporaire avec toutes les colonnes requises et en renvoyant toutes les colonnes sans valeur lorsque la valeur null est transmise à la procédure.

Dans ma procédure, il y avait une 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 l'information de colonne dans mon cas après avoir utilisé le truc FMTONLY OFF.

Ceci est une table temporaire que j'ai créée pour obtenir les données vides . Maintenant, je reçois les informations de la colonne

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

Entity Framework tentera d'obtenir les colonnes en exécutant votre procédure stockée, en passant NULL pour chaque argument. 

  1. Assurez-vous que la procédure stockée renverra quelque chose dans toutes les circonstances. Notez qu'il était peut-être plus judicieux pour Entity Framework d'exécuter le proc stocké avec des valeurs par défaut pour les arguments, par opposition à NULL.

  2. ER effectue les opérations suivantes pour obtenir les métadonnées de la table:

    SET FMTONLY ON

  3. Cela rompra votre procédure stockée dans diverses circonstances, notamment si elle utilise une table temporaire.

  4. Donc, pour obtenir un résultat de type complexe; veuillez essayer en ajoutant

    SET FMTONLY OFF;

Cela a fonctionné pour moi - espérons que cela fonctionne pour vous aussi.

Référé de https://social.msdn.Microsoft.com/Forums/en-US/e7f598a2-6827-4b27-a09d-aefe733b48e6/entity-model-add-function-import-stored-stored-procedure-procedure-procedure-crurns-no- colonnes? forum = adodotnetentityframework

0
Kiran Nandan

Dans mon cas, SET FMTONLY OFF ne fonctionnait pas. La méthode que j’ai suivie est la suivante: j’ai pris une sauvegarde de la procédure stockée d’origine et ne l'ai remplacée que par le nom de la colonne, comme dans la requête ci-dessous.

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

Après cette modification, créez une nouvelle importation de fonction, type complexe dans le cadre d'entité . Une fois la fonction d'importation et le type complexe créés, remplacez la requête ci-dessus par votre procédure stockée d'origine.

0
Darshan Jadyal

Dans mon cas, ajouter SET NOCOUNT ON; en haut de la procédure a résolu le problème. C'est la meilleure pratique quand même.

0
Endrju