2013-04-26 72 views
1

有幾個SQL服務器有存儲過程,例如Microsoft SQL Server或PostgreSQL。還有一些實現存儲過程調用的客戶端對象(Delphi中的TADOStoredProc,.NET Framework中的SqlCommand等)。是否從文本字符串執行存儲過程?

我一直想問的問題是:

存儲與它們的參數的二進制表示在特別有效的方式始終執行的程序,或者是一個代表存儲過程參數始終轉換爲普通超高級對象文本字符串和存儲過程始終通過將此純文本字符串發送到SQL服務器來執行? (讓我們以一種技術爲例 - 讓它成爲SQL Server和ADO.NET)。

我注意到,對ADO.NET過程的參數名稱沒有任何意義 - 只有他們的創作順序很重要,這讓我想用純文本字符串的想法。

更新@Alex K.

我測試過下面的.NET代碼:

CREATE PROCEDURE paramtest 
@par1 nvarchar(50), 
@par2 nvarchar(50), 
@par3 nvarchar(50) 
AS 
    SELECT Res = '@par1 = ' + @par1 + '; @par2 = ' + @par2 + '; @par3 = ' + @par3 
    RETURN 555 

using System; 
using System.Data.SqlClient; 
using System.Data; 

namespace SqlParamTest 
{ 
    class Program 
    { 
     private static void addParam(SqlCommand cmd, string parameterName, ParameterDirection direction, SqlDbType dbType, int size, object value) 
     { 
      SqlParameter par = new SqlParameter(parameterName, dbType, size); 
      par.Direction = direction; 
      par.Value = value; 
      cmd.Parameters.Add(par); 
     } 

     static void Main(string[] args) 
     { 
      using (SqlConnection conn = new SqlConnection(@"Data Source=localhost\sqlexpress;Initial Catalog=test;Integrated Security=True")) 
      { 
       SqlCommand cmd = conn.CreateCommand(); 
       cmd.CommandType = CommandType.StoredProcedure; 
       cmd.CommandText = "paramtest"; 
       addParam(cmd, "@par3", ParameterDirection.Input, SqlDbType.NVarChar, 50, "third"); 
       addParam(cmd, "@par2", ParameterDirection.Input, SqlDbType.NVarChar, 50, "second"); 
       addParam(cmd, "@par1", ParameterDirection.Input, SqlDbType.NVarChar, 50, "first"); 
       addParam(cmd, "@Return", ParameterDirection.ReturnValue, SqlDbType.Int, 0, null); 
       conn.Open(); 
       SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection); 
       if (rdr.Read()) Console.WriteLine((string)rdr["Res"]); 
       rdr.Close(); 
       Console.WriteLine("Return value: {0}", cmd.Parameters["@Return"].Value); 
      } 
      Console.ReadKey(); 
     } 
    } 
} 

,是的,它保持在一個正確的方法參數,但我認爲,.NET是增加了額外的參數檢查,因爲在Delphi中的代碼如下:

procedure TMyClass.Test(Conn: TADOConnection); 
var SP:TADOStoredProc; 
begin 
    SP := TADOStoredProc.Create(nil); 
    try 
    SP.Connection := Conn; 
    SP.ProcedureName := 'paramtest'; 
    SP.Parameters.CreateParameter('@whatthehell', ftString, pdInput, 50, 'one'); 
    SP.Parameters.CreateParameter('@AnotherCrap', ftString, pdInput, 50, 'two'); 
    SP.Parameters.CreateParameter('?', ftString, pdInput, 50, 'three'); 
    SP.ExecProc; 
    finally 
    SP.Free; 
    end; 
end; 

回報:

@par1 = one; @par2 = two; @par3 = three 

,不抱怨缺少的參數。

pdReturnValue僅在該參數在任何其他參數之前創建時纔有效。

回答

1

不知道你尋找什麼回答,存儲過程命令文本&參數傳遞給驅動程序/提供者或本地通過ADO.NET將其格式化爲TDS(表格數據流)RPC(遠程過程調用)消息然後傳遞到正在使用任何網絡協議的服務器;管道,tcp/ip等。數據以二進制流的形式發送。

來自微軟的TDS規格is available如果您有興趣。

SQLCommand調用存儲過程確實需要一個參數名稱,其OLEDB/ODBC是隻關心的順序和使用?作爲參數佔位符,而不是@NAME

有關順序

在您的例子的順序是不相關的,因爲你提供與該PARAMS正確的名稱服務器,所以這是被髮送到服務器:

exec paramtest @par3=N'third',@par2=N'second',@par1=N'first' 

這是服務器找出正確參數/順序的足夠信息。

如果改爲

addParam(cmd, "@xxpar3", 
addParam(cmd, "@xxpar2", 
addParam(cmd, "@xxpar1", 

服務器會檢測到,它並沒有名爲xxxpar* PARAM和失敗,一個「失蹤@ PAR1」的錯誤。

如果修改addParam所以沒有設置paramater名.NET將創建默認:

exec paramtest @Parameter1=N'third',@Parameter2=N'second',@Parameter3=N'first' 

這將導致上述錯誤。

如果您修改了addParam,所以它沒有設置參數名稱,然後覆蓋自動的名稱;

cmd.Parameters.Add(par); 
par.ParameterName = ""; 

這是得到執行:導致

@par1 = third; @par2 = second; @par3 = first 

exec paramtest N'third',N'second',N'first' 

我不知道德爾福做什麼... SQL Server附帶的完整版本的工具叫SQL事件探查器,它顯示發送到服務器實例的文本數據,以便您可以看到究竟發生了什麼。 What profiler to use with sql express?

+0

Alex,我已經更新了有關參數順序的問題。 – Paul 2013-04-29 14:04:25

+0

更新了上述內容。 – 2013-04-29 15:30:28