Wie kann ich eine Liste von Parametern aus einer gespeicherten Prozedur in SQL Server abrufen?

StackOverflow https://stackoverflow.com/questions/33761

  •  09-06-2019
  •  | 
  •  

Frage

Gibt es mit C# und System.Data.SqlClient eine Möglichkeit, eine Liste von Parametern abzurufen, die zu einer gespeicherten Prozedur auf einem SQL Server gehören, bevor ich sie tatsächlich ausführe?

Ich habe ein Szenario mit mehreren Umgebungen, in dem es mehrere Versionen desselben Datenbankschemas gibt.Beispiele für Umgebungen könnten „Entwicklung“, „Staging“ und „Produktion“ sein.„Entwicklung“ wird eine Version der gespeicherten Prozedur haben und „Staging“ wird eine andere haben.

Ich möchte lediglich überprüfen, ob ein Parameter vorhanden ist, bevor ich ihm einen Wert übergebe und die gespeicherte Prozedur aufrufe.Diese SqlException zu vermeiden, anstatt sie abfangen zu müssen, ist für mich ein Plus.

Joshua

War es hilfreich?

Lösung

Sie können SqlCommandBuilder.DeriveParameters() verwenden (siehe SqlCommandBuilder.DeriveParameters – Parameterinformationen für eine gespeicherte Prozedur abrufen – ADO.NET-Tutorials) oder es gibt Hier entlang was nicht so elegant ist.

Andere Tipps

Du willst das SqlCommandBuilder.DeriveParameters(SqlCommand) Methode.Beachten Sie, dass hierfür ein zusätzlicher Roundtrip zur Datenbank erforderlich ist und es daher zu erheblichen Leistungseinbußen kommt.Sie sollten erwägen, die Ergebnisse zwischenzuspeichern.

Ein Beispielaufruf:

using (SqlConnection conn = new SqlConnection(CONNSTRING))
using (SqlCommand cmd = new SqlCommand("StoredProc", conn)) {
   cmd.CommandType = CommandType.StoredProcedure;
   SqlCommandBuilder.DeriveParameters(cmd);

   cmd.Parameters["param1"].Value = "12345";

   // ....
}

Obwohl es nicht genau das ist, was Sie wollen, finden Sie hier einen Beispielcode, der die Methode SqlConnection.GetSchema() verwendet, um alle mit einer Datenbank verknüpften gespeicherten Prozeduren und anschließend alle Parameternamen und -typen für jede gespeicherte Prozedur zurückzugeben.Das folgende Beispiel lädt dies einfach in Variablen.Beachten Sie, dass dadurch auch alle gespeicherten Systemprozeduren zurückgegeben werden, was möglicherweise unerwünscht ist.

Steve

    public void LoadProcedureInfo()
    {
        SqlConnection connection = new SqlConnection();

        ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["ConnectionString"];

        connection.ConnectionString = settings.ConnectionString;
        connection.Open();

        DataTable procedureDataTable = connection.GetSchema("Procedures");
        DataColumn procedureDataColumn = procedureDataTable.Columns["ROUTINE_NAME"];

        if (procedureDataColumn != null)
        {
            foreach (DataRow row in procedureDataTable.Rows)
            {
                String procedureName = row[procedureDataColumn].ToString();

                DataTable parmsDataTable = connection.GetSchema("ProcedureParameters", new string[] { null, null, procedureName });

                DataColumn parmNameDataColumn = parmsDataTable.Columns["PARAMETER_NAME"];
                DataColumn parmTypeDataColumn = parmsDataTable.Columns["DATA_TYPE"];

                foreach (DataRow parmRow in parmsDataTable.Rows)
                {
                    string parmName = parmRow[parmNameDataColumn].ToString();
                    string parmType = parmRow[parmTypeDataColumn].ToString();
                }
            }
        }
    }

Sie können das SqlCommandBuilder-Objekt verwenden und die DeriveParameters-Methode aufrufen.

Im Grunde müssen Sie ihm einen Befehl übergeben, der so eingerichtet ist, dass er Ihren gespeicherten Prozess aufruft, und er greift auf die Datenbank zu, um die Parameter zu ermitteln und die entsprechenden Parameter in der Parameters-Eigenschaft des SqlCommand zu erstellen

BEARBEITEN: Ihr seid alle zu schnell!!

SqlCommandBuilder.DeriveParameters(command)

Diese Aussage tut, was ich brauche.

Hier ist ein vollständiges Codebeispiel für die Art und Weise, wie ich dieses Problem gelöst habe.

Public Sub GetLogEntriesForApplication(ByVal settings As FilterSettings,
                              Optional ByVal RowGovernor As Integer = -1)

    Dim command As New SqlCommand("GetApplicationActions", 
        New SqlConnection(m_environment.LoggingDatabaseConnectionString))
    Dim adapter As New SqlDataAdapter(command)

    Using command.Connection

        With command

            .Connection.Open()
            .CommandType = CommandType.StoredProcedure

            SqlCommandBuilder.DeriveParameters(command)

            With .Parameters

                If settings.FilterOnLoggingLevel Then
                    If .Contains("@loggingLevel") Then
                        .Item("@loggingLevel").Value = settings.LoggingLevel
                    End If
                End If

                If settings.FilterOnApplicationID Then
                    If .Contains("@applicationID") Then
                        .Item("@applicationID").Value = settings.ApplicationID
                    End If
                End If

                If settings.FilterOnCreatedDate Then
                    If .Contains("@startDate") Then
                        .Item("@startDate").Value = settings.CreatedDate.Ticks
                    End If
                End If

                If settings.FilterOnEndDate Then
                    If .Contains("@endDate") Then
                        .Item("@endDate").Value = settings.EndDate.Ticks
                    End If
                End If

                If settings.FilterOnSuccess Then
                    If .Contains("@success") Then
                        .Item("@success").Value = settings.Success
                    End If
                End If

                If settings.FilterOnProcess Then
                    If settings.Process > -1 Then
                        If .Contains("@process") Then
                            .Item("@process").Value = settings.Process
                        End If
                    End If
                End If

                If RowGovernor > -1 Then
                    If .Contains("@topRows") Then
                        .Item("@topRows").Value = RowGovernor
                    End If
                End If

            End With

        End With

        adapter.TableMappings.Clear()
        adapter.TableMappings.Add("Table", "ApplicationActions")
        adapter.TableMappings.Add("Table1", "Milestones")

        LogEntries.Clear()
        Milestones.Clear()
        adapter.Fill(m_logEntryData)

    End Using

End Sub

Mark hat die beste Implementierung von DeriveParameters.Wie er sagte, stellen Sie sicher, dass Sie den Cache mögen dieses Tutorial.

Ich denke jedoch, dass dies eine gefährliche Möglichkeit ist, Ihr ursprüngliches Problem der Datenbank-Sproc-Versionierung zu lösen.Wenn Sie die Signatur einer Prozedur durch Hinzufügen oder Entfernen von Parametern ändern möchten, sollten Sie einen der folgenden Schritte ausführen:

  • Codieren Sie abwärtskompatibel, indem Sie Standardwerte verwenden (für neue Parameter) oder indem Sie einfach einen Parameter ignorieren (für gelöschte Parameter).Dadurch wird sichergestellt, dass Ihr Clientcode immer jede Version Ihrer gespeicherten Prozedur aufrufen kann.
  • Versionieren Sie die Prozedur explizit nach Namen (damit Sie my_proc und my_proc_v2 haben).Dadurch wird sichergestellt, dass Ihr Client-Code und Ihre Sprocs synchron bleiben.

Sich auf DeriveParameters zu verlassen, um zu überprüfen, welche Version des Sproc Sie verwenden, scheint meiner Meinung nach das falsche Tool für den Job zu sein.

Alle diese ADO.NET-Lösungen fordern die Codebibliothek auf, die Metadaten der Datenbank in Ihrem Namen abzufragen.Wenn Sie diesen Leistungseinbruch trotzdem in Kauf nehmen wollen, sollten Sie vielleicht einfach ein paar Hilfsfunktionen schreiben, die aufrufen

Select count(*) from information_schema.parameters 
where ...(proc name =.. param name=...) (pseudo-code)

Oder generieren Sie Ihre Parameter vielleicht sogar basierend auf der Parameterliste, die Sie zurückerhalten.Diese Technik funktioniert mit mehreren Versionen von MS SQL und manchmal auch anderen ANSI SQL-Datenbanken.

Ich verwende DeriveParameters jetzt seit ein paar Jahren mit .NET 1.1 und 2.0 und es hat jedes Mal wunderbar funktioniert.

Jetzt arbeite ich an meiner ersten Aufgabe mit .NET 3.5 und habe gerade eine hässliche Überraschung gefunden:DeriveParameters erstellt alle Parameter mit SqlDbType „Variant“ und nicht mit den richtigen SqlDbTypes.Dies führt zu einer SqlException, wenn versucht wird, SPs mit numerischen Parametern auszuführen, da SQL Server 2005 angibt, dass SQL-Variantentypen nicht implizit in int-Werte (oder smallint-Werte oder numerische Werte) konvertiert werden können.

Ich habe gerade denselben Code mit .NET CF 2.0 und SQL Server 2000 getestet und wie erwartet funktioniert, indem ich jedem Parameter den richtigen SqlDbType zugewiesen habe.

Ich habe .NET 2.0-Apps mit SQL Server 2005-Datenbanken getestet, es handelt sich also nicht um ein SQL Server-bezogenes Problem, es muss also etwas mit .NET 3.5 zusammenhängen

Irgendwelche Ideen?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top