web-dev-qa-db-de.com

Die gespeicherte Prozedur gibt statt der Ergebnismenge int zurück

Ich habe eine gespeicherte Prozedur, die dynamische Auswahl enthält. Etwas wie das:

ALTER PROCEDURE [dbo].[usp_GetTestRecords] 
    [email protected] int = 0, 
    [email protected] int = 0
    @groupId nvarchar(10) = 0
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @query  NVARCHAR(max)

    SET @query = 'SELECT * FROM CUSTOMERS WHERE Id = ' + @groupId
    /* This actually contains a dynamic pivot select statement */

    EXECUTE(@query);
END

Im SSMS läuft die gespeicherte Prozedur einwandfrei und zeigt die Ergebnismenge.

In C # wird mit Entity Framework eine int anstelle von IEnumerable zurückgegeben.

private void LoadTestRecords()
{
    TestRecordsDBEntities dataContext = new TestRecordsDBEntities();
    string id = ddlGroupId.SelectedValue;

    List<TestRecord> list = dataContext.usp_GetTestRecords(id); //This part doesn't work returns int
    GridView1.DataSource = list;
}

Generierte Funktion für usp_GetTestRecords

public virtual int usp_GetTestRecords(string groupId)
{
    var groupIdParameter = groupId != null ?
        new ObjectParameter("groupId", groupId) :
        new ObjectParameter("groupId", typeof(string));

    return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("usp_GetTestRecords", groupIdParameter);
}
23
Rod

Entity Framework kann nicht erkennen, was Ihre gespeicherte Prozedur zurückgibt. Ich habe erfolgreich eine Tabellenvariable erstellt, die die Daten Ihrer SELECT-Anweisung widerspiegelt. Fügen Sie einfach in die Tabellenvariable ein und wählen Sie dann aus dieser Tabellenvariablen aus. EF sollte es abholen.

13
Rob

Ich bekomme dies, wenn ich eine gespeicherte Prozedur habe, die einen "exec" -Aufruf in eine temporäre Tabelle enthält, wie zum Beispiel:

insert into #codes (Code, ActionCodes, Description)
exec TreatmentCodes_sps 0

Es scheint, dass Entity Framework verwirrt wird, was von der Prozedur zurückgegeben werden soll. Die Lösung, auf die ich gestoßen bin, ist, dies oben im Sproc hinzuzufügen:

SET FMTONLY OFF

Danach ist alles gut.

19
Yelnic

Ich habe das gleiche Problem und fand eine Lösung hier

  1. Wechseln Sie zu Ihrem .edmx
  2. Unter Modellbrowser-Fenster/Funktionsimporten finden Sie Ihre Prozedur und doppelklicken Sie darauf
  3. Ändern Sie den Rückgabetyp nach Wunsch
  4. Speichern Sie .edmx und überprüfen Sie den Rückgabetyp erneut.

 Screenshot

Es sollte das sein, was Sie jetzt brauchen.

16
蕭為元

Siehe die Antwort von Ladislav Mrnka in diesem Beitrag zum Stack Overflow https://stackoverflow.com/a/7131344/4318324

Ich hatte das gleiche Grundproblem.

Hinzufügen 

SET FMTONLY OFF

Eine Prozedur, die Sie während des Imports importieren möchten, behebt dieses Problem. Es empfiehlt sich, die Zeile anschließend zu entfernen, es sei denn, der Zweck der Datenbank besteht ausschließlich darin, ein Schema für EF (Entity Framework) bereitzustellen.

Der Hauptgrund für die Vorsicht ist, dass EF diese Einstellung verwendet, um Datenmutationen beim Abrufen von Metadaten zu verhindern.

Wenn Sie Ihr Entitätsmodell aus einer Datenbank aktualisieren, können Prozeduren mit dieser Zeile möglicherweise die Daten in dieser Datenbank aktualisieren, indem Sie einfach versuchen, das Schema abzurufen.

Ich wollte dazu noch eine weitere Anmerkung hinzufügen, damit der andere Link nicht vollständig durchsucht werden kann.

wenn Sie versuchen möchten, FMTONLY zu verwenden, sind hier ein paar Dinge zu beachten.

 wenn FMTONLY eingeschaltet ist: 
 1) Nur das Schema wird zurückgegeben (keine) Zeilen .
 Ähnlich wie das Hinzufügen einer falschen false-Anweisung zu Ihrer where-Klausel (dh "where 1 = 0") 
 2) Flusssteuerungsanweisungen werden ignoriert 

Beispiel

 fmtonly auf 

 setzen, wenn 1 = 1 
 begin 
 Wählen Sie 1 a 
 end 
 sonst 
 begin 
 Wählen Sie 1 a, 2 b 
 Ende 

, während 1 = 1 
 Wählen Sie 1 c 

Das obige gibt KEINE Zeilen und die Metadaten für jede der drei Abfragen zurück

Aus diesem Grund schlagen einige Leute vor, die Funktion so einzustellen, dass die Flusskontrolle nicht beachtet wird

 wenn 1 = 0 
 begin 
 fmtonly ausschalten 
 ende 

Tatsächlich könnten Sie dies verwenden, um eine Logik einzuführen, die dies verfolgt

 setze fmtonly aus 
 declare @g varchar (30) 
 set @g = 'fmtonly wurde auf off gesetzt' 

 wenn 1 = 0 
 begin 
 Fmtonly ausschalten 
 set @g = 'fmtonly wurde auf on gesetzt
 end 

 select @g 

Denken Sie SEHR SORGFÄLTIG, bevor Sie versuchen, diese Funktion zu verwenden, da dies veraltet ist und SQL möglicherweise extrem schwer zu folgen ist

die wichtigsten Konzepte, die verstanden werden müssen, sind folgende

 1. EF schaltet FMTONLY ein, um zu verhindern, dass MUTATING-Daten gespeicherte Prozeduren ausführen 
 wenn es sie während eines Modell-Updates ausführt .
 (woraus folgt) 

 2. Wenn Sie FMTONLY in einer beliebigen Prozedur ausschalten, die EF versucht, einen Schema-Scan durchzuführen, ___. (möglicherweise ANY und EACHONE) führt das Potenzial zur Veränderung der Datenbank ein 
 Daten, wann immer * jemand * versucht, ihr Datenbankmodell zu aktualisieren .
6
wode

Entity Framework gibt automatisch einen Skalarwert zurück, wenn Ihre gespeicherte Prozedur keinen Primärschlüssel in Ihrer Ergebnismenge enthält. Daher müssen Sie eine Primärschlüsselspalte in Ihre select-Anweisung einschließen oder eine temporäre Tabelle mit einem Primärschlüssel erstellen, damit Entity Framework eine Ergebnismenge für Ihre gespeicherte Prozedur zurückgeben kann.

4
hoangvu

Ich hatte das gleiche Problem, ich änderte den Namen der Rückgabefelder nach dem Schlüsselwort 'AS' und behandelte mein Problem. Ein Grund für dieses Problem ist das Benennen von Spaltennamen mit für SQL Server reservierten Schlüsselwörtern.

Das Beispiel ist Brachen:

ALTER PROCEDURE [dbo].[usp_GetProducts]

AS
BEGIN

 SET NOCOUNT ON;

 SELECT 
      , p.Id
      , p.Title
      , p.Description AS 'Description'

    FROM dbo.Products AS p
END
1
Armen Hovsepian

Wenn Sie Ihre Modellklasse für Ihre gespeicherte Prozedur generiert haben, haben Sie versehentlich das Ergebnis der skalaren Rückgabe ausgewählt. Sie sollten Ihre gespeicherte Prozedur aus Ihrem Entitätsmodell entfernen und dann die gespeicherte Prozedur erneut hinzufügen. Im Dialog für die gespeicherte Prozedur können Sie den erwarteten Rückgabetyp auswählen.NichtBearbeiten Sie einfach den generierten Code. Dies kann jetzt funktionieren. Der generierte Code kann jedoch ersetzt werden, wenn Sie andere Änderungen an Ihrem Modell vornehmen.

1
Claies

Ich habe ein wenig darüber nachgedacht und denke, ich habe eine bessere/einfachere Antwort

Wenn Sie einen Komplex gespeichert haben, der das Entity-Framework schwierig gestaltet (für aktuelle Versionen von Entity Framework, die das FMTONLY-Tag verwenden, um ein Schema zu erwerben)

Überlegen Sie, ob Sie zu Beginn Ihrer gespeicherten Prozedur Folgendes tun möchten.

-- Wobei [columnlist] mit dem Schema übereinstimmt, das EF für Ihre gespeicherte Prozedur abrufen soll 

 wenn 1 = 0 
 begin 
 wählen 
 [Spaltenliste] 
 from [table list and joins] 
 wobei 1 = 0 
 Ende 

wenn Sie die Ergebnismenge in eine Tabellenvariable laden möchten, können Sie Folgendes tun, um Ihr Schema synchron zu halten

 deklariert @tablevar als Tabelle 
 (
 blah int 
, moreblah varchar (20) 
) 
__. wenn 1 = 0 
 begin 
 Wählen Sie * aus @Tablevar 
 Ende 

...
-- Laden Sie Daten in @Tablevar 
 Wählen Sie * aus @Tablevar 
1
wode

Nun, ich hatte auch dieses Problem, aber nach stundenlanger Online-Suche hat keine der oben genannten Methoden geholfen. Endlich erfuhr ich, dass es passieren wird, wenn Ihre Store-Prozedur einige Parameter als Null erhält und Fehler in der Abfrageausführung auftreten. Entity Framework generiert eine Methode für die Speicherprozedur, indem das komplexe Entitätsmodell definiert wird. Aufgrund dieses Nullwerts gibt Ihre Store-Prozedur einen Int-Wert zurück. 

Überprüfen Sie Ihre Store-Prozedur, indem Sie entweder leere Ergebnismenge mit Nullwerten angeben. Es wird Ihr Problem beheben. Hoffnungsvoll.

0
Murxiii Javed

Wenn Sie dies tun müssen, ist es möglicherweise besser, nur einen Teil des dbcontext zu erstellen und selbst die C # -Funktion zu erstellen, die SqlQuery verwendet, um die benötigten Daten zurückzugeben. Vorteile gegenüber einigen anderen Optionen sind:

  1. Sie müssen nichts ändern, wenn das Modell aktualisiert wird
  2. Wird nicht überschrieben, wenn Sie es direkt in der generierten Klasse tun (jemand oben erwähnt dies als Option :))
  3. Sie müssen dem Prozess selbst nichts hinzufügen, das jetzt oder später Nebenwirkungen haben könnte

Beispielcode:

 public partial class myEntities
    {
       public List<MyClass> usp_GetTestRecords(int _p1, int _p2, string _groupId)
       {
          // fill out params
          SqlParameter p1 = new SqlParameter("@p1", _p1);
          ...
          obj[] parameters = new object[] { p1, p2, groupId };

          // call the proc
          return this.Database.SqlQuery<MyClass>(@"EXECUTE usp_GetTestRecords @p1, @p2, @groupId", parameters).ToList();
       }
    }
0
user441521

Die beste Lösung, die ich gefunden habe, ist ein wenig zu betrügen.

Kommentieren Sie in der Store-Prozedur alles, setzen Sie eine erste Zeile mit einem select [foo]='', [bar]='' etc ... Aktualisieren Sie nun das Modell, wechseln Sie zur zugeordneten Funktion, wählen Sie den komplexen Typ aus und klicken Sie auf Get Column Information und dann auf Create Complex Type.

Kommentieren Sie nun die Fälschung und entkommentieren Sie den eigentlichen Geschäftsvorgang.

0
Max Favilli

Während des Imports

SET FMTONLY ON Kann zur Aufnahme des sp-Schemas verwendet werden.

Wenn Sie den SP ändern und den neuen aktualisieren möchten, sollten Sie die alte definierte Funktion aus der EDMX-Datei (aus XML) löschen, da SP zwar aus dem Modellbrowser gelöscht wird, sie jedoch nicht in EDMX gelöscht wird. Zum Beispiel;

    <FunctionImport Name="GetInvoiceByNumber"     ReturnType="Collection(Model.Invoice_Result)">
       <Parameter Name="InvoiceNumber" Mode="In" Type="Int32" />
    </FunctionImport>

Ich hatte das gleiche Problem, und wenn ich den FuctionImport-Tag des entsprechenden sp total lösche, wurde das Modell richtig aktualisiert. Sie können das Tag finden, indem Sie den Funktionsnamen in Visual Studio suchen.

0
Betul Bas

Ändern Sie einfach zu 

ALTER PROCEDURE [dbo].[usp_GetTestRecords] 
    [email protected] int = 0, 
    [email protected] int = 0
    @groupId nvarchar(10) = 0
AS
BEGIN
    SET NOCOUNT ON;


    SELECT * FROM CUSTOMERS WHERE Id =  @groupId

END
0
Nezam

Ich weiß, dass dies ein alter Thread ist, aber falls jemand die gleichen Probleme hat, werde ich mein Leid erzählen.

Um das Problem zu finden, führen Sie den sql-Profiler aus, wenn Sie Ihre gespeicherte Prozedur hinzufügen. Dann können Sie sehen, welches Entity-Framework als Parameter zum Generieren Ihrer Ergebnismenge übergeben wird. Ich stelle mir fast immer vor, es werden Nullparameterwerte übergeben. Wenn Sie schnell SQL erzeugen, indem Sie Zeichenfolgenwerte und Parameterwerte verketten, und einige sind null, dann bricht die SQL und es wird kein Rückgabesatz angezeigt. 

Ich brauche keine temporären Tabellen oder irgendetwas, nur einen Exec-Befehl.

Ich hoffe es hilft

0
Rob White

Möglicherweise haben Sie Glück, den Modellbrowser zu öffnen. Dann gehen Sie zu Funktionsimporte, doppelklicken Sie auf die betreffende gespeicherte Prozedur, klicken Sie dann manuell auf "Spalteninformationen abrufen" und dann auf "Neuen komplexen Typ erstellen". Dies beseitigt normalerweise das Problem.

0