2008-08-29 6 views
13

Используя C# и System.Data.SqlClient, есть способ получить список параметров, относящихся к хранимой процедуре на SQL Server, прежде чем я на самом деле выполнить его?Как получить список параметров из хранимой процедуры в SQL Server

У меня есть сценарий «multi-environment», где есть несколько версий одной и той же схемы базы данных. Примерами сред могут быть «Разработка», «Проведение», & «Производство». «Разработка» будет иметь одну версию хранимой процедуры, а «Staging» будет иметь другую.

Все, что я хочу сделать, это проверить, должен ли быть параметр перед передачей ему значения и вызовом хранимой процедуры. Избегая того, что исключение SqlException вместо того, чтобы его поймать, является плюсом для меня.

Джошуа

ответ

8

Вы можете использовать SqlCommandBuilder.DeriveParameters() (см SqlCommandBuilder.DeriveParameters - Get Parameter Information for a Stored Procedure - ADO.NET Tutorials) или есть this way, который не столь элегантно.

+1

Ссылка на сайт Дэвида Хейдена (первая ссылка) не существует, и похоже, что она не перенесена из его старого блога. – JoeFletch 2013-08-08 12:07:53

2
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 
2

Вы можете использовать объект SqlCommandBuilder и вызвать метод DeriveParameters.

В основном вам нужно передать ему команду, то есть установка для вызова хранимой процедуры, и она попала в БД, чтобы открыть параметры, и создать соответствующие параметры в свойстве параметров SqlCommand

EDIT: Вы слишком быстро!

14

Вы хотите метод 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"; 

    // .... 
} 
5

Хотя его не совсем то, что вы хотите, вот пример кода, который использует метод 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(); 
       } 
      } 
     } 
    } 
1

Марк имеет лучшую реализацию DeriveParameters. По его словам, убедитесь, что вы кешируете, как в this tutorial.

Однако, я думаю, что это опасный способ решения вашей исходной проблемы с версией базы данных sproc. Если вы собираетесь изменить подпись процедуры путем добавления или удаления параметров, необходимо выполнить одно из следующих действий:

  • кодекса в обратной совместимости способа с использованием значений по умолчанию (для нового Params) или просто игнорируя параметр (для удаленных параметров).Это гарантирует, что код клиента всегда может вызывать любую версию хранимой процедуры.
  • Явно версия процедура по имени (так что у вас будут my_proc и my_proc_v2). Это гарантирует, что ваш код клиента и sprocs останутся в синхронизации.

Опираясь на DeriveParameters, чтобы проверить, какая версия sproc вы используете, кажется неправильным инструментом для работы, IMHO.

0

Все эти решения ADO.NET просят библиотеку кода запрашивать метаданные базы данных от вашего имени. Если вы собираетесь принять, что производительность удара, так или иначе, может быть, вы просто должны написать некоторые вспомогательные функции, которые вызывают

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

Или, может быть, даже генерировать свои параметры на основе списка паров вы получаете обратно. Этот метод будет работать с несколькими версиями MS SQL, а иногда и с другими базами данных ANSI SQL.

0

Я использую DeriveParameters с .NET 1.1 и 2.0 с тех пор, как пару лет, и каждый раз работал как шарм.

Теперь я работаю над своим первым заданием с .NET 3.5, и только что нашел и уродливо удивил: DeriveParameters создает все параметры с помощью SqlDbType «Вариант», а не собственно SqlDbTypes. Это создает исключение SqlException при попытке выполнить SP с числовыми параметрами, поскольку SQL Server 2005 говорит, что типы sql-вариантов не могут быть преобразованы в значения int (или smallint или numeric).

Я только что протестировал один и тот же код с .NET CF 2.0 и SQL Server 2000 и работал должным образом, назначив правильный SqlDbType для каждого параметра.

я испытал .NET 2.0 приложения против SQL Server 2005 баз данных, так что это не SQL Server связанные проблемы, поэтому он должен быть что-то связано с .NET 3.5

Любые идеи?

+0

Просто обнаружил, что эта проблема связана с проблемой CompactFramework. Просто прошел тест в приложении WindowsForms и работал, как ожидалось, но тот же самый код запускался из проекта SmartDEvice, и все параметры были выбраны как «вариант». :( – VictorEspina 2009-10-01 15:54:10

Смежные вопросы