簡體   English   中英

如何從SQL Server中的存儲過程檢索參數列表

[英]How can I retrieve a list of parameters from a stored procedure in SQL Server

使用C#和System.Data.SqlClient,有沒有辦法在實際執行之前檢索屬於SQL Server上的存儲過程的參數列表?

我有一個“多環境”場景,其中有相同數據庫架構的多個版本。 環境的示例可以是“開發”,“分段”和“生產”。 “開發”將有一個版本的存儲過程,“Staging”將有另一個版本。

我想要做的就是在傳遞一個值並調用存儲過程之前驗證參數是否存在。 避免SqlException而不是必須捕獲它對我來說是一個加分。

約書亞

您需要SqlCommandBuilder.DeriveParameters(SqlCommand)方法。 請注意,它需要額外的數據庫往返,因此它的性能有點顯着。 您應該考慮緩存結果。

一個示例電話:

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";

   // ....
}

您可以使用SqlCommandBuilder.DeriveParameters()(請參閱SqlCommandBuilder.DeriveParameters - 獲取存儲過程的參數信息 - ADO.NET教程 )或者這種方式不是那么優雅。

雖然它不完全是您想要的,但這里有一些示例代碼,它使用SqlConnection.GetSchema()方法返回與數據庫關聯的所有存儲過程,然后返回每個存儲過程的所有參數名稱和類型。 下面的示例只是將其加載到變量中。 請注意,這也會返回所有“系統”存儲過程,這可能是不可取的。

史蒂夫

    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();
                }
            }
        }
    }
SqlCommandBuilder.DeriveParameters(command)

這句話做了我需要的。

以下是我解決此問題的完整代碼示例。

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

您可以使用SqlCommandBuilder對象,並調用DeriveParameters方法。

基本上你需要傳遞一個命令,設置為調用你的存儲過程,它將命中數據庫以發現參數,並在SqlCommand的Parameters屬性中創建適當的參數

編輯:你太快了!!

Mark擁有DeriveParameters的最佳實現。 正如他所說,請確保像本教程中一樣緩存。

但是,我認為這是解決數據庫sproc版本化原始問題的危險方法。 如果要通過添加或刪除參數來更改過程的簽名,則應執行以下操作之一:

  • 通過使用默認值(對於新的參數)或通過簡單地忽略參數(對於已刪除的參數)以向后兼容的方式編碼。 這可確保您的客戶端代碼始終可以調用任何版本的存儲過程。
  • 按名稱顯式地對過程進行版本化(因此您將擁有my_proc和my_proc_v2)。 這可確保您的客戶端代碼和sprocs保持同步。

依靠DeriveParameters來驗證你正在使用的sproc的哪個版本似乎是錯誤的工具,恕我直言。

幾年以來,我一直在使用帶有.NET 1.1和2.0的DeriveParameters,每次都像魅力一樣。

現在我正在使用.NET 3.5進行我的第一次任務,並且發現並且令人驚訝:DeriveParameters使用SqlDbType“Variant”創建所有參數,而不是正確的SqlDbTypes。 這在嘗試使用數字參數執行SP時會創建SqlException,因為SQL Server 2005說sql-variant類型不能被隱式轉換為int(或smallint或numeric)值。

我剛剛使用.NET CF 2.0和SQL Server 2000測試了相同的代碼,並按預期工作,為每個參數分配正確的SqlDbType。

我已經針對SQL Server 2005數據庫測試了.NET 2.0應用程序,因此不是與SQL Server相關的問題,所以它必須與.NET 3.5相關

有任何想法嗎?

所有這些ADO.NET解決方案都要求代碼庫代表您查詢數據庫的元數據。 如果你打算在任何時候取得性能打擊,也許你應該只編寫一些調用的輔助函數

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

或者甚至可以根據您返回的參數列表生成參數。 此技術適用於多個版本的MS SQL,有時還適用於其他ANSI SQL數據庫。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM