65 votes

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 qu'EF n'aime pas cela, et j'ai listé spécifiquement toutes les colonnes qui seraient retournées. Pourtant, il n'aime toujours pas ça. Qu'est-ce que je fais de mal ? Je veux juste que EF soit capable de détecter les colonnes retournées par la procédure stockée pour pouvoir créer les classes dont j'ai besoin.

Veuillez voir 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

155voto

Ladislav Mrnka Points 218632

EF ne supporte pas l'importation de procédures stockées à partir desquelles sont construits les jeux de résultats :

  • 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 déclencher des modifications dans la base de données. C'est pourquoi 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 ensemble 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 (ou de requête dynamique construite) et 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éfinir manuellement le type complexe retourné (je suppose que cela devrait fonctionner)
  • Utiliser un hack et juste pour ajouter la procédure stockée mettre à 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 pas les données car ces modifications seront exécutées pendant l'importation ! Après une importation réussie, supprimez ce hack.

9 votes

Cela a fonctionné pour une de mes procédures, mais pas pour l'autre. J'ai fini par modifier ma procédure pour qu'elle renvoie un ensemble de résultats vide avec les mêmes types de données pendant que j'ajoutais la procédure au concepteur, puis je suis revenu en arrière une fois la procédure ajoutée avec succès.

3 votes

Le point clé pour moi était "EF doit l'exécuter", mon proc avait une erreur lorsqu'il était exécuté avec des paramètres nuls.

3 votes

Dans mon cas, il s'agissait en fait de régler SET FMTONLY OFF.

28voto

Muhammad Omar Points 1204

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

IF 1=0 BEGIN
    SET FMTONLY OFF
END

Pourquoi mon jeu de données typées n'aime-t-il pas les tables temporaires ?

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

1 votes

Après des heures et des heures, ceci a résolu mon problème, merci beaucoup.

0 votes

Assurez-vous qu'après avoir fait cela, votre fonction peut effectivement s'exécuter avec toutes les valeurs NULL. EF va essayer d'exécuter votre requête avec toutes les valeurs NULL. Faites une trace ; vous verrez. Nous ne savions pas que la fonction lançait des erreurs de dépassement d'entier sur des entrées NULL. Nous n'avons peut-être jamais réalisé que c'était la vraie réponse.

0 votes

Si cette solution ne résout pas votre problème, il est possible que l'assistant EF "Get Column Information" se termine avant que votre sp ne soit terminé - ce qui donne également le résultat "no columns returned". La solution est d'accélérer temporairement votre sp en ajoutant une clause WHERE par exemple pour que les tables temporaires ne renvoient qu'un ensemble de données limité. Cela a fonctionné pour moi. N'oubliez pas de supprimer la clause WHERE après que EF ait récupéré/sauvegardé les informations sur les colonnes.

13voto

Vous pouvez également 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 être capable de reconnaître le type de colonnes retournées.

1voto

tmanthey Points 1887

Ce que j'ajouterais, c'est que :

L'importation échoue également si les procédures stockées ont des paramètres et ne renvoient aucun ensemble de résultats pour les valeurs de paramètres par défaut.

Ma procédure stockée avait deux paramètres flottants et ne retournait rien lorsque les deux paramètres étaient égaux à 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 de garantir qu'elle renvoie quelques lignes, quels que soient les paramètres réels.

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

0 votes

Il se peut également que certains d'entre vous exécutent des procédures stockées complexes de type curseur qui nécessitent plus de 15 secondes pour obtenir des résultats, et que l'assistant de l'adaptateur de table de données s'arrête après n'avoir obtenu aucune ligne dans les 15 secondes. Une solution simple consiste à cibler une instruction de sélection complexe dans votre procédure stockée et à la préfixer avec "top 1" afin qu'elle renvoie immédiatement une seule ligne. Construisez votre adaptateur de jeu de données avec cela, puis modifiez votre procédure stockée en sélection complète et vous devriez être prêt.

1voto

Rachael Points 83

Note complémentaire intéressante : j'ai eu 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 m'a déstabilisé lors de l'observation initiale de mes deux SProcs : l'un utilisant des tables temporaires et l'autre des variables de table.

(SET FMTONLY OFF n'a jamais fonctionné pour moi, alors j'ai simplement modifié temporairement mes SProcs pour obtenir les informations sur les colonnes, plutôt que de m'embêter avec le hack du côté EF, juste pour info).

Ma meilleure option a été de créer manuellement le type complexe et d'y associer la fonction d'importation. Cela a très bien fonctionné, la seule différence étant qu'une FactoryMethod supplémentaire pour créer les propriétés a été incluse dans le Designer.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X