web-dev-qa-db-fra.com

Pourquoi Entity Framework ne peut-il pas voir les informations de colonne de ma procédure stockée?

J'ai la procédure stockée suivante et quand j'essaye de faire fonctionner l'importation, elle dit que ma procédure stockée ne renvoie aucune colonne. Qu'est-ce que je rate? Aucune suggestion? 

Le Proc: 

ALTER PROCEDURE [healthc].[ev_kc_Products_Search]
(
    @SearchString   VARCHAR(1000)
)
AS
SET NOCOUNT ON

    DECLARE @SQL    VARCHAR(max),
        @SQL1   VARCHAR(max),
        @Tag    VARCHAR(5)

    CREATE TABLE #T
    (   ID      INT,
        VendorName  VARCHAR(255),
        ItemName        VARCHAR(255),
        Type        VARCHAR(2),
        Sequence        TINYINT
    )


 SET @SQL = '

    INSERT  #T

    SELECT  VendorID ID,
        Name VendorName,
        NULL ItemName,
        ''V'' Type,
        0 Sequence
    FROM    tblVendors
    WHERE   '+REPLACE(@SQL1,@Tag,'Name')+'

    UNION ALL

    BLAH BLAH BLAH'


 EXEC(@SQL)


 SELECT ID, VendorName, ItemName, Type FROM #T
30
RodneyRoadRunner

Essayez d’ajouter cette ligne au début de votre procédure stockée:

SET FMTONLY OFF

Vous pouvez le supprimer une fois l'importation terminée.

49
benshabatnoam

Qu'est-ce qui se passe ici dans les coulisses?

  1. Lors de l’importation de fonctions -> Obtenir des informations sur la colonne ... Visual Studio exécute la procédure stockée avec toutes les valeurs param définies comme NULL (vous pouvez le vérifier par l’intermédiaire de MS SQL Profiler).

  2. En effectuant l'étape 1, les colonnes résultantes de la procédure stockée sont renvoyées avec leur type de données et leurs informations de longueur.

  3. Une fois les informations de la colonne extraites, cliquez sur le bouton 'Créer un nouveau type de complexe' pour créer le type de complexe du SP en conflit.

Dans votre cas, les paramètres proc stockés ne peuvent pas être annulés. Par conséquent, l'appel de Visual Studio échoue et ne renvoie aucune colonne.

Comment gérer ça?

 SI (1 = 0) 
 COMMENCER 
 SET FMTONLY OFF 
 si @ param1 est null et que @ param2 est null, alors 
 commencer
 sélectionner
 cast (null comme varchar (10)) comme Column1, 
 cast (null as bit) comme Column2, 
 cast (null comme décimal) comme Column3 
 END 
 END 

Pour être précis (dans votre cas):

 SI (1 = 0) 
 COMMENCER 
 SET FMTONLY OFF 
 si @SearchString est null, alors 
 COMMENCER
 sélectionner
 cast (null as int) en tant qu'ID, 
 cast (null en tant que varchar (255)) en tant que VendorName, 
 cast (null en tant que varchar (255)) en tant que ItemName, 
 cast (null comme varchar (2)) comme Type 
 END 
 END 

Référence: http://mysoftwarenotes.wordpress.com/2011/11/04/entity-framework-4-%E2%80%93-the-selected-stored-procedure-returns-no-columns-part-2/

35
Sudhanshu Singh

en complétant et en faisant simple @benshabatnoam, il suffit de mettre le code suivant au début: 

IF (1=2)
    SET FMTONLY OFF

Remarque: cela fonctionne dans EF 6.1.3 et Visual Studio 2015 Update 3.

6
Mahmoud Moravej

Vous avez ce problème en raison de la table temporaire . Tout ce que vous avez à faire est: 1. Modifiez votre procédure stockée pour renvoyer le statemant sélectionné sans la table temporaire . 2. Allez dans la fonction import et obtenez les informations sur la colonne . 3. Modifiez votre procédure stockée de nouveau à l'original.

2
benshabatnoam

Pour que EF trouve les colonnes rapidement et correctement, commentez la clause where dans votre procédure stockée (ajoutez éventuellement un TOP 1 pour l’empêcher de tout renvoyer), ajoutez le processus à EF et créez le type complexe, puis décommentez le où clause à nouveau.

1
SteveCav

J'aimerais ajouter quelque chose à la réponse de Sudhanshu Singh: cela fonctionne très bien, mais si vous avez des structures plus complexes, combinez-le avec une déclaration de table.

J'ai utilisé avec succès les éléments suivants (placez-le au tout début de votre procédure stockée):

CREATE PROCEDURE [EY].[MyStoredProc] 
AS
BEGIN

SET NOCOUNT ON;

IF (1=0) 
BEGIN 
    SET FMTONLY OFF 
        BEGIN
            -- declaration + dummy query 
            -- to allow EF obtain complex data type:
            DECLARE @MyStoredProcResult TABLE(
                ID      INT,
                VendorName  VARCHAR(255),
                ItemName    VARCHAR(255),
                Type        VARCHAR(2),
                Sequence    TINYINT
                );
            SELECT * FROM @MyStoredProcResult WHERE (1=0)
        END
END   

-- your code follows here (SELECT ... FROM ...)
-- this code must return the same columns/data types
--
-- if you require a temp table / table variable like the one above
-- anyway, add the results during processing to @MyStoredProcResult
-- and then your last statement in the SP can be
-- SELECT * FROM @MyStoredProcResult
END

Remarque que le 1=0 garantit qu'il n'est jamais exécuté, mais que l'EF en déduit la structure.

Après avoir enregistré votre procédure stockée, ouvrez le fichier EDMX dans Visual Studio, actualisez le modèle de données, accédez au navigateur de modèles Entity Frameworks. Dans le navigateur de modèle, localisez votre procédure stockée, ouvrez la boîte de dialogue "Éditer une importation de fonction", sélectionnez "Renvoie une collection de ... Complexe", puis cliquez sur le bouton "Obtenir les informations sur la colonne".

Il devrait montrer la structure telle que définie ci-dessus. Si tel est le cas, cliquez sur "Créer un nouveau type de complexe" pour en créer un avec le nom de la procédure stockée, par exemple. "MyStoredProc_Result" (ajouté par "_Result"). 

Vous pouvez maintenant le sélectionner dans la liste déroulante de "Renvoie une collection de ... Complex" dans la même boîte de dialogue.

Chaque fois que vous devez mettre à jour quelque chose, commencez par mettre à jour le SP, puis vous pourrez revenir à la boîte de dialogue Éditer une fonction d'importation et cliquer sur le bouton "Mettre à jour" (vous n'avez pas besoin de tout recréer de nouveau).

1
Matt

Si vous utilisez une table temporaire, l'entité (EDMX) ne peut pas comprendre ce qui se passe.

Donc, renvoyez le résultat vide avec le nom de la colonne, commentez toutes vos procédures stockées et exécutez-le dans le gestionnaire SQL, puis récupérez le type complexe dans visual studio. Après l'enregistrement, rétablissez l'état initial de votre procédure stockée (c'est-à-dire sans commentaire).

bonne chance/

1
Ehud Grand

J'ai eu ce problème, ce que je devais faire était de créer un type de table défini par l'utilisateur et de le renvoyer.

CREATE TYPE T1 AS TABLE 
(  ID      INT,
    VendorName  VARCHAR(255),
    ItemName        VARCHAR(255),
    Type        VARCHAR(2),
    Sequence        TINYINT
);
GO

Votre procédure stockée va maintenant ressembler à ceci:

ALTER PROCEDURE [healthc].[ev_kc_Products_Search]
(
@SearchString   VARCHAR(1000)
)
AS
SET NOCOUNT ON

DECLARE @SQL    VARCHAR(max),
    @SQL1   VARCHAR(max),
    @Tag    VARCHAR(5)

@T [schema].T1

SET @SQL = 'SELECT  VendorID ID,
    Name VendorName,
    NULL ItemName,
    ''V'' Type,
    0 Sequence
    FROM    tblVendors
    WHERE   '+REPLACE(@SQL1,@Tag,'Name')+'
    UNION ALL
    BLAH BLAH BLAH'

INSERT INTO @T
EXEC(@SQL)

SELECT ID, VendorName, ItemName, Type FROM @T
0
Wesley Coetzee

Il suffit d’ajouter l’instruction select sans la citation, d’exécuter le proc stocké, de mettre à jour le modèle, d’éditer l’importation de votre fonction et d’obtenir des informations sur les colonnes. Cela devrait remplir les nouvelles colonnes. Mettez à jour le jeu de résultats, revenez à votre procédure stockée et supprimez la liste de sélection que vous venez d'ajouter. Et exécutez le proc stocké. De cette façon, vos colonnes seront renseignées dans le jeu de résultats . Voir ci-dessous où ajouter la liste de sélection sans guillemets.

    ALTER PROCEDURE [healthc].[ev_kc_Products_Search]
(
    @SearchString   VARCHAR(1000)
)

AS
SET NOCOUNT ON;
SELECT  VendorID ID,
        Name VendorName,
        NULL ItemName,
        ''V'' Type,
        0 Sequence
    FROM    tblVendors

DECLARE @SQL    VARCHAR(max),
    @SQL1   VARCHAR(max),
    @Tag    VARCHAR(5)

CREATE TABLE #T
(   ID      INT,
    VendorName  VARCHAR(255),
    ItemName        VARCHAR(255),
    Type        VARCHAR(2),
    Sequence        TINYINT
)

SET @SQL = '

INSERT  #T

SELECT  VendorID ID,
    Name VendorName,
    NULL ItemName,
    ''V'' Type,
    0 Sequence
FROM    tblVendors
WHERE   '+REPLACE(@SQL1,@Tag,'Name')+'

UNION ALL

BLAH BLAH BLAH'

EXEC (@SQL)

SELECT ID, VendorName, ItemName, Type FROM #T

J'espère que cela aide quelqu'un là-bas.

0
Yoky