2008-08-29 43 views
13

Sử dụng C# và System.Data.SqlClient, có cách nào để truy xuất danh sách tham số thuộc về một thủ tục được lưu trữ trên SQL Server trước khi thực sự Thực hiện nó?Làm thế nào tôi có thể lấy danh sách tham số từ thủ tục được lưu trữ trong SQL Server

Tôi có một kịch bản "đa môi trường" trong đó có nhiều phiên bản của cùng một lược đồ cơ sở dữ liệu. Ví dụ về môi trường có thể là "Phát triển", "Dàn dựng", & "Sản xuất". "Phát triển" sẽ có một phiên bản của thủ tục lưu sẵn và "Dàn dựng" sẽ có một phiên bản khác.

Tất cả những gì tôi muốn làm là xác thực rằng một tham số sẽ có ở đó trước khi chuyển cho nó một giá trị và gọi thủ tục được lưu trữ. Tránh SqlException hơn là phải bắt nó là một lợi thế đối với tôi.

Joshua

Trả lời

2
SqlCommandBuilder.DeriveParameters(command) 

Tuyên bố này làm những gì tôi cần nó.

Đây là mẫu mã đầy đủ cho cách tôi giải quyết vấn đề này.

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

Bạn có thể sử dụng đối tượng SqlCommandBuilder và gọi phương thức DeriveParameters.

Về cơ bản bạn cần phải vượt qua nó một lệnh, đó là thiết lập để gọi proc lưu trữ của bạn, và nó sẽ nhấn DB để khám phá các thông số, và tạo ra các thông số thích hợp trong các tài sản thông số của SqlCommand

EDIT: Bạn đang quá nhanh !!

14

Bạn muốn phương thức SqlCommandBuilder.DeriveParameters(SqlCommand). Lưu ý rằng nó yêu cầu thêm một chuyến đi vòng vào cơ sở dữ liệu, do đó, nó là một hit hiệu suất hơi đáng kể. Bạn nên xem xét bộ nhớ đệm kết quả.

Một cuộc gọi Ví dụ:

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

Mặc dù không phải của mình một cách chính xác những gì bạn muốn, sau đây là một số mẫu mã có sử dụng phương pháp SqlConnection.GetSchema() để trả lại tất cả các thủ tục lưu trữ liên kết với một cơ sở dữ liệu, và rồi sau đó tất cả các tên và kiểu tham số cho mỗi thủ tục lưu sẵn. Ví dụ dưới đây chỉ tải điều này vào các biến. Lưu ý rằng điều này cũng trả về tất cả các "hệ thống" được lưu trữ thủ tục, mà có thể không được mong muốn.

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(); 
       } 
      } 
     } 
    } 
1

Đánh dấu đã thực hiện tốt nhất của DeriveParameters. Như anh ấy đã nói, hãy đảm bảo bộ nhớ cache của bạn giống như trong this tutorial.

Tuy nhiên, tôi nghĩ đây là một cách nguy hiểm để giải quyết vấn đề gốc của bạn về phiên bản cơ sở dữ liệu sproc. Nếu bạn muốn thay đổi chữ ký của quy trình bằng cách thêm hoặc xóa thông số, bạn nên thực hiện một trong các thao tác sau:

  • Mã theo cách tương thích ngược bằng cách sử dụng mặc định (cho tham số mới) hoặc đơn giản là bỏ qua một param (cho params bị xóa).Điều này đảm bảo rằng mã máy khách của bạn luôn có thể gọi bất kỳ phiên bản nào của quy trình được lưu trữ của bạn.
  • Phiên bản rõ ràng quy trình theo tên (vì vậy bạn sẽ có my_proc và my_proc_v2). Điều này đảm bảo rằng mã máy khách và sprocs của bạn vẫn được đồng bộ hóa.

Dựa vào DeriveParameters để xác thực phiên bản của sproc bạn đang sử dụng có vẻ như công cụ sai cho công việc, IMHO.

0

Tất cả các giải pháp ADO.NET này đều yêu cầu thư viện mã truy vấn siêu dữ liệu của cơ sở dữ liệu thay cho bạn. Nếu bạn đang đi để lấy rằng hiệu suất trúng dù sao đi nữa, có lẽ bạn chỉ nên viết một số chức năng helper mà gọi

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

Hoặc thậm chí có thể tạo ra các thông số của bạn dựa trên danh sách param bạn trở lại. Kỹ thuật này sẽ làm việc với nhiều phiên bản của MS SQL và đôi khi các cơ sở dữ liệu SQL ANSI khác.

0

Tôi đã sử dụng DeriveParameters với .NET 1.1 và 2.0 từ một vài năm nay, và làm việc như một sự quyến rũ mọi lúc.

Bây giờ tôi đang làm bài tập đầu tiên của mình với .NET 3.5 và chỉ tìm thấy và ngạc nhiên xấu: DeriveParameters đang tạo tất cả các tham số với SqlDbType "Biến thể", thay vào đó là SqlDbTypes đúng. Điều này tạo ra một SqlException khi cố gắng thực thi SP với các tham số số, vì SQL Server 2005 nói rằng các kiểu biến thể sql không thể được chuyển đổi thành các giá trị int (hoặc smallint hoặc số).

Tôi vừa thử nghiệm cùng một mã với .NET CF 2.0 và SQL Server 2000, và làm việc như mong đợi, gán SqlDbType chính xác cho mỗi tham số.

tôi đã thử nghiệm NET 2.0 ứng dụng chống SQL Server 2005 cơ sở dữ liệu, vì vậy không phải là một SQL Server vấn đề liên quan, vì vậy nó phải được cái gì đó liên quan với .NET 3.5

Bất kỳ ý tưởng?

+0

Chỉ phát hiện ra rằng vấn đề này là một vấn đề liên quan đến CompactFramework. Chỉ cần chạy một thử nghiệm trong một ứng dụng WindowsForms và làm việc như mong đợi, nhưng chính xác cùng một mã chạy từ một dự án SmartDEvice, trả về tất cả các tham số như 'biến thể'. :( – VictorEspina

Các vấn đề liên quan