所以在C#中使用存储过程我有如下代码(省略连接代码):
string sql = "GetClientDefaults";
SqlCommand cmd = new SqlCommand(sql);
cmd.CommandType = CommandType.StoredProcedure; //<-- DO I NEED THIS??
cmd.Parameters.AddWithValue("@computerName", computerName);
其中sql是存储过程的名称。现在,这个代码似乎在有和没有注释行的情况下工作得很好。
那么,我需要这条线吗?设置它有一些性能(或其他)的好处吗?不设置或将其设置为文本是否有益处?
答案 0 :(得分:15)
根据this blog post中的测试,当您使用CommandType.Text
时,SQL Server将通过将语句包装在sp_executesql中来为您进行参数化。但是当您使用CommandType.StoredProcedure
时,您将对其进行参数化,从而为数据库保存一些工作。后一种方法更快。
修改强>
<强>设置强>
我自己做了一些测试,这是结果。
创建此程序:
create procedure dbo.Test
(
@Text1 varchar(10) = 'Default1'
,@Text2 varchar(10) = 'Default2'
)
as
begin
select @Text1 as Text1, @Text2 as Text2
end
使用SQL Server Profiler为其添加跟踪。
然后使用以下代码调用它:
using System;
using System.Data;
using System.Data.SqlClient;
namespace ConsoleApplication2
{
class Program
{
static void Main()
{
CallProcedure( CommandType.Text );
CallProcedure( CommandType.StoredProcedure );
}
private static void CallProcedure(CommandType commandType)
{
using ( SqlConnection connection = new SqlConnection("Data Source=localhost;Initial Catalog=Test;Integrated Security=SSPI;") )
{
connection.Open();
using ( SqlCommand textCommand = new SqlCommand("dbo.Test", connection) )
{
textCommand.CommandType = commandType;
textCommand.Parameters.AddWithValue("@Text1", "Text1");
textCommand.Parameters.AddWithValue("@Text2", "Text2");
using ( IDataReader reader = textCommand.ExecuteReader() )
{
while ( reader.Read() )
{
Console.WriteLine(reader["Text1"] + " " + reader["Text2"]);
}
}
}
}
}
}
}
<强>结果
在这两种情况下,使用RPC进行调用。
以下是跟踪使用CommandType.Text
显示的内容:
exec sp_executesql N'dbo.Test',N'@Text1 nvarchar(5),@Text2 nvarchar(5)',@Text1=N'Text1',@Text2=N'Text2'
以下是使用CommandType.StoredProcedure
的结果:
exec dbo.Test @Text1=N'Text1',@Text2=N'Text2'
正如您所看到的,文本调用包含在对sp_executesql
的调用中,因此它已正确参数化。这当然会产生轻微的开销,因此我先前声明使用CommandType.StoredProcedure
更快仍然有效。
另一个值得注意的事情,也就是这里的交易破坏者,当我创建没有默认值的过程时,我得到以下错误:
Msg 201,Level 16,State 4,Procedure Test,Line 0 Procedure或 函数'Test'需要参数'@ Text1',这是未提供的。
原因是如何创建对sp_executesql
的调用,因为您可以看到参数已声明并初始化,但它们未被使用。对于工作电话,它应该是这样的:
exec sp_executesql N'dbo.Test @Text1, @Text2',N'@Text1 nvarchar(5),@Text2 nvarchar(5)',@Text1=N'Text1',@Text2=N'Text2'
意思是,当您使用CommandType.Text
时,您必须将参数添加到CommandText
,除非您始终希望使用默认值。
所以,回答你的问题
CommandType.StoredProcedure
的速度更快。CommandType.Text
,则必须将参数名称添加到对过程的调用中,除非您希望使用默认值。答案 1 :(得分:7)
实际上存在巨大差异。如果指定命令类型StoredProcedure
,则添加到SqlCommand的任何参数都将是添加过程调用的参数。如果将其保留为Text
,则参数将添加到批次,而不是程序。为了说明这一点,我们创建一个虚拟过程:
create procedure usp_test
@p1 char(10) = 'foo',
@p2 int = 42
as
select @p1, @p2;
go
然后编译这个小小的C#应用程序:
static void Main(string[] args)
{
ExecWithType(CommandType.Text);
ExecWithType(CommandType.StoredProcedure);
}
static void ExecWithType(CommandType type)
{
using (SqlConnection conn = new SqlConnection(Settings.Default.connString))
{
conn.Open();
using (SqlCommand cmd1 = new SqlCommand("usp_test", conn))
{
cmd1.CommandType = type;
cmd1.Parameters.AddWithValue("@p1", "bar");
cmd1.Parameters.AddWithValue("@p2", 24);
using (SqlDataReader rdr = cmd1.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine("Type: {0} Result: @p1: {1} @p2: {2}", type, rdr[0], rdr[1]);
}
}
}
}
}
结果是:
Type: Text Result: @p1: foo @p2: 42
Type: StoredProcedure Result: @p1: bar @p2: 24
哎哟!对于CommandType.Text
设置,虽然参数已传递到批次,但它们未传递到过程 。多小时调试乐趣的来源......
答案 2 :(得分:6)
您可以将其设置为允许ADO.NET帮助您。当您使用CommandType.StoredProcedure
时,您必须将CommandText
等于存储过程名称。
例如,这个:
YourSqlCommand.CommandType = CommandType.StoredProcedure;
YourSqlCommand.CommandText = "dbo.YourStoredProc";
相当于:
YourSqlCommand.CommandText = "exec dbo.YourStoredProc";
答案 3 :(得分:3)
CommandType不是特定于SQL Server。它是IDbCommand接口的一个属性,它指示底层提供程序以特定方式处理CommandText。虽然SQL Server可能会将单字名称视为过程,但您不应期望这在其他提供程序中起作用。
通常,您应该更喜欢使用提供程序生成的类(如DbCommand)而不是像SqlCommand这样的特定类。这样,您只需更改配置文件中的提供程序字符串即可定位不同的数据库。