web-dev-qa-db-fra.com

EF ne peut pas déduire le schéma de retour de la procédure stockée en sélectionnant dans une table #temp

Supposons ce qui suit:

CREATE PROCEDURE [MySPROC]
AS 
BEGIN

CREATE TABLE #tempSubset(
    [MyPrimaryKey] [bigint]  NOT NULL,
    [OtherColumn]  [int]     NOT NULL)

INSERT INTO #tempSubset (MyPrimaryKey, OtherColumn) 
    SELECT SomePrimaryKey, SomeColumn 
    FROM   SomeHugeTable
    WHERE  LimitingCondition = true

SELECT MyPrimaryKey, OtherColumn 
FROM   #tempSubset
WHERE  SomeExpensiveCondition = true

END

Lorsque je génère une fonction import ou mappe un type de retour, EF ne génère pas de type complexe ou me dit:

La procédure ou la fonction stockée sélectionnée ne renvoie aucune colonne

Comment surmonter cela?

D'autres réponses suggèrent en utilisant des variables de table (ne va pas le faire pour des raisons de performances) en simulant le schéma de retour et en commentant la véritable procédure stockée , d'autres suggèrent en faisant similaire avec vues ... mais il doit y avoir un moyen de le faire sans avoir à ajouter des frais généraux inutiles ou à me forcer à interrompre une procédure stockée pour mettre à jour le modèle?

37
JoeBrockhaus
CREATE PROCEDURE [MySPROC]
AS 
BEGIN

--supplying a data contract
IF 1 = 2 BEGIN
    SELECT
        cast(null as bigint)  as MyPrimaryKey,
        cast(null as int)    as OtherColumn
    WHERE
        1 = 2  
END

CREATE TABLE #tempSubset(
    [MyPrimaryKey] [bigint]  NOT NULL,
    [OtherColumn]  [int]     NOT NULL)

INSERT INTO #tempSubset (MyPrimaryKey, OtherColumn) 
    SELECT SomePrimaryKey, SomeColumn 
    FROM   SomeHugeTable
    WHERE  LimitingCondition = true

SELECT MyPrimaryKey, OtherColumn 
FROM   #tempSubset
WHERE  SomeExpensiveCondition = true

END

Fournir un faux contrat de données pour l'ensemble de résultats est le moyen le plus simple, le plus propre et le plus rapide de résoudre le problème. Ce même problème existe également dans les contrôles de source de données dans SSIS. .NET lira le jeu de résultats à partir de la section "contrat" ​​inaccessible de la requête et fournira les métadonnées pour le type complexe. Aucun impact sur les performances et pas besoin de commenter le SQL qui fait le travail réel.

60
BrianKrahenbuhl

L'ajout de cela en haut de la définition de procédure stockée:

SET FMTONLY OFF

Exemple:

SET FMTONLY OFF

CREATE TABLE #tempTable (
    ...
)

...

SELECT * FROM #tempTable 
47
RominNoodleSamurai

Solution 1 Utilisez une variable de table au lieu d'une table temporaire.

Solution 2 Utilisez le réglage FMTONLY désactivé; Commande SQL dans la procédure et vous obtiendrez les informations de colonne pour créer un nouveau type complexe.

Solution 3 Ce n'est pas un bon moyen, mais c'est un moyen très simple. Ajoutez simplement une instruction select avec des données factices et elle ne s'exécutera pas car 1 = 0.

vous pouvez vérifier les détails sur ce lien

10
user3364545

Ceci est incomplet mais lorsque la désactivation de fmtonly ne fonctionne pas, vous pouvez générer le contrat de données à l'aide de ce qui suit:

        SELECT * 
        FROM tempdb.sys.columns 
        WHERE [object_id] = OBJECT_ID(N'tempdb..#u');

        select case  system_type_id 
        when 62 then 'cast(null as float) as ' 
        when 175 then 'cast(null as char(' + cast(max_length as varchar(50)) + ')) as ' 
        when 167 then 'cast(null as varchar(' + cast(max_length as varchar(50)) + ')) as ' 
        when 56 then 'cast(null as int) as ' 
        when 104 then 'cast(null as bit) as ' 
        when 106 then 'cast(null as decimal(' + cast(precision as varchar(50)) + ',' + cast(scale as varchar(50)) + ')) as ' 
        when 40 then 'cast(null as date) as '            
        end
        + name + ','
        from  tempdb.sys.columns 
        WHERE [object_id] = OBJECT_ID(N'tempdb..#u');
0
Mark Pearson