wake-up-neo.com

Warum kann Entity Framework die Spalteninformationen meiner gespeicherten Prozedur nicht sehen?

Ich habe die folgende gespeicherte Prozedur, und wenn ich versuche, Funktionsimport auszuführen, werden in meiner gespeicherten Prozedur keine Spalten angezeigt. Was vermisse ich? Irgendwelche Vorschläge? 

Der 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

Fügen Sie diese Zeile am Anfang Ihrer gespeicherten Prozedur ein:

SET FMTONLY OFF

Sie können dies entfernen, nachdem Sie den Import abgeschlossen haben.

49
benshabatnoam

Was passiert hier hinter den Kulissen?

  1. Während des Imports der Funktion -> Spalteninformationen abrufen ... Visual Studio führt die gespeicherte Prozedur mit allen Parameterwerten als NULL aus (Sie können dies mithilfe von MS SQL Profiler überprüfen).

  2. In Schritt 1 werden die resultierenden Spalten der gespeicherten proc mit Datentyp und Längeninformationen zurückgegeben.

  3. Sobald die Spalteninformationen abgerufen wurden, wird durch Klicken auf die Schaltfläche "Neuen komplexen Typ erstellen" der komplexe Typ des SP erstellt.

In Ihrem Fall sind die gespeicherten proc-Parameter nicht nullfähig. Daher schlägt der Aufruf von Visual Studio fehl und gibt keine Spalten zurück.

Wie soll ich damit umgehen?

 IF (1 = 0) 
 BEGIN 
 FMTONLY OFF 
 Wenn @ param1 Null ist und @ param2 Null ist, dann 
 Start
 wählen
 cast (null als varchar (10)) als Spalte1, 
 Besetzung (null als Bit) als Spalte2, 
 cast (null als Dezimalzahl) als Column3 
 END 
 END 

Um genau zu sein (in Ihrem Fall):

 IF (1 = 0) 
 BEGIN 
 FMTONLY OFF 
 Wenn @SearchString NULL ist, dann 
 START
 wählen
 cast (null als int) als ID, 
 cast (null als varchar (255)) als VendorName, 
 cast (null als varchar (255)) als ItemName 
 cast (null als varchar (2)) als Typ 
 END 
 END 

Referenz: 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

geben Sie einfach den folgenden Code an den Anfang: 

IF (1=2)
    SET FMTONLY OFF

Hinweis: Es funktioniert in EF 6.1.3 und Visual Studio 2015 Update 3

6
Mahmoud Moravej

Sie haben dieses Problem aufgrund der temporären Tabelle. Alles, was Sie tun müssen, ist:. 1. Ändern Sie Ihre gespeicherte Prozedur, um den Select-Status ohne die temporäre Tabelle zurückzugeben. 2. Gehen Sie zur Funktion importieren und rufen Sie die Spalteninformationen ab . 3. Ändern Sie Ihre gespeicherte Prozedur wieder in das Original.

2
benshabatnoam

Als schnelle und schmutzige Methode, um EF zu veranlassen, die Spalten zu finden, kommentieren Sie die where-Klausel in Ihrer gespeicherten Prozedur aus (fügen Sie möglicherweise eine TOP 1 hinzu, um das Zurückgeben von alles zu stoppen), fügen Sie die Prozedur zur EF hinzu und erstellen Sie den Complex Type wo wieder Klausel.

1
SteveCav

Ich möchte Sudhanshu Singhs Antwort etwas hinzufügen: Es funktioniert sehr gut, aber wenn Sie komplexere Strukturen haben, kombinieren Sie es mit einer Tabellendeklaration.

Ich habe erfolgreich Folgendes verwendet (platzieren Sie es ganz am Anfang Ihres gespeicherten Vorgangs):

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

Hinweis dass der 1=0 garantiert, dass er niemals ausgeführt wird, aber die EF zieht die Struktur davon ab.

Nachdem Sie Ihre gespeicherte Prozedur gespeichert haben, öffnen Sie die EDMX-Datei in Visual Studio, aktualisieren Sie das Datenmodell und rufen Sie den Entity Frameworks-Modellbrowser auf. Suchen Sie im Modellbrowser nach Ihrer gespeicherten Prozedur, öffnen Sie den Dialog "Funktionsimport bearbeiten", wählen Sie "Gibt eine Sammlung von ... Komplexen zurück", und klicken Sie auf die Schaltfläche "Spalteninformationen abrufen".

Es sollte die Struktur wie oben definiert angezeigt werden. Wenn dies der Fall ist, klicken Sie auf "Neuen komplexen Typ erstellen", und es wird ein solcher mit dem Namen der gespeicherten Prozedur erstellt, z. "MyStoredProc_Result" (angehängt durch "_Result"). 

Jetzt können Sie es in der Combobox von "Liefert eine Sammlung von ... Komplexen" im selben Dialog auswählen.

Wenn Sie etwas aktualisieren müssen, aktualisieren Sie zuerst SP. Anschließend können Sie zum Dialogfeld "Funktionsimport bearbeiten" zurückkehren und auf die Schaltfläche "Aktualisieren" klicken (Sie müssen nicht alles von Grund auf neu erstellen).

1
Matt

Wenn Sie eine temporäre Tabelle verwenden, kann die Entität (EDMX) nicht verstehen, was los ist.

Geben Sie also ein leeres Ergebnis mit dem Spaltennamen zurück, kommentieren Sie Ihre gesamte gespeicherte Prozedur aus und führen Sie sie im SQL-Manager aus. Rufen Sie dann den komplexen Typ in Visual Studio ab. Setzen Sie die gespeicherte Prozedur nach dem Speichern in den ursprünglichen Zustand zurück (unkommentiert).

viel Glück/

1
Ehud Grand

Ich hatte dieses Problem. Ich musste einen benutzerdefinierten Tabellentyp erstellen und diesen zurückgeben.

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

Ihre gespeicherte Prozedur sieht jetzt so aus:

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

Fügen Sie einfach die select-Anweisung ohne das Angebot hinzu, führen Sie die gespeicherte Prozedur aus, rufen Sie das Modell aktualisieren auf, bearbeiten Sie den Import Ihrer Funktion und erhalten Sie Spalteninformationen. Dies sollte die neuen Spalten füllen. Aktualisieren Sie die Ergebnismenge und kehren Sie zu Ihrer gespeicherten Prozedur zurück und entfernen Sie die gerade hinzugefügte Auswahlliste. Und führe die gespeicherte Prozedur aus. Auf diese Weise werden Ihre Spalten in der Ergebnismenge aufgefüllt. Sehen Sie unten, wo Sie die Auswahlliste ohne Anführungszeichen hinzufügen müssen.

    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, Lieferantenname, Artikelname, Typ FROM #T

Ich hoffe, das hilft jemandem da draußen.

0
Yoky