当我读书学习C#(可能是一些旧的Visual Studio 2005
书籍)时,我遇到过建议,每次执行SQL调用时都要使用SqlCommand.Prepare
(无论是{a {{1}我在SQL SERVER 2005/2008上使用/ SELECT
或UPDATE
并将参数传递给它。 但它真的如此?
每次都应该这样做吗?或者有时候?
它是一个参数传递还是五个或二十个是否重要?
如果有的话应该提供什么?它是否会引人注目(我一直在这里使用INSERT
并在那里跳过它,从来没有任何问题或明显的差异)。
为了问题,这是我使用的常用代码,但这更像是一个普遍的问题。
SqlCommand.Prepare
补充说明:
如果我像下面的代码一样移动public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) {
const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni, @varStopaOdniesienia) AS 'Benchmark'";
using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) {
using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) {
sqlQuery.Prepare();
sqlQuery.Parameters.AddWithValue("@varPortfelID", varPortfelID);
sqlQuery.Parameters.AddWithValue("@varStopaOdniesienia", varStopaOdniesienia);
sqlQuery.Parameters.AddWithValue("@data", data);
sqlQuery.Parameters.AddWithValue("@varBenchmarkPoprzedni", varBenchmarkPoprzedni);
using (var sqlQueryResult = sqlQuery.ExecuteReader())
if (sqlQueryResult != null) {
while (sqlQueryResult.Read()) {
}
}
}
}
,则抛出必须明确声明大小的异常,这基本上会让我认为首先使用sqlQuery.Prepare()
会使它无用吗?有人可以使用我的示例显示正确的用法吗?
sqlQuery.Prepare()
我该怎么做?通过在参数旁边添加.size并执行varPortfel.Lenght(如果它是字符串等)?
答案 0 :(得分:12)
来自MSDN文档:
“在致电Prepare之前,请指定 中的每个参数的数据类型 声明准备。对于每一个 具有可变长度的参数 数据类型,您必须设置大小 属性到所需的最大尺寸。 如果这些准备,则准备返回错误 条件不符合。
如果你之后调用了Execute方法 调用Prepare,任何参数值 这个值大于值 由Size属性指定的是 自动截断到 原始指定的大小 参数,没有截断错误 归还。
输出参数(无论是否准备好) not)必须有用户指定的数据 类型。如果指定可变长度 数据类型,您还必须指定 最大尺寸。“
此外,“如果是CommandType property设置为TableDirect, 准备什么都不做。如果是CommandType 设置为StoredProcedure,调用 准备应该成功,......“
这通常用于确保最终用户不使用SQL注入技术来添加或删除数据库中不需要的信息。
我调查了一下,查看了这篇文章http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.prepare.aspx。您的问题是您需要在运行.Prepare()之前定义参数,然后在运行.Prepare()之后设置参数。现在你正在做两件事。我会尝试这样的事情(注意我没有测试它,所以我的语法可能有点偏。)
public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) {
const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni, @varStopaOdniesienia) AS 'Benchmark'";
using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) {
using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) {
sqlQuery.Parameters.Add("@varPortfelID");
sqlQuery.Parameters.Add("@varStopaOdniesienia");
sqlQuery.Parameters.Add("@data");
sqlQuery.Parameters.Add("@varBenchmarkPoprzedni");
sqlQuery.Prepare();
sqlQuery.ExecuteNonQuery();//This might need to be ExecuteReader()
sqlQuery.Parameters[0].Value = varPortfelID;
sqlQuery.Parameters[1].Value = varStopaOdniesienia;
sqlQuery.Parameters[2].Value = data;
sqlQuery.Parameters[3].Value = varBenchmarkPoprzedni;
using (var sqlQueryResult = sqlQuery.ExecuteReader())
if (sqlQueryResult != null) {
while (sqlQueryResult.Read()) {
}
}
}
}
答案 1 :(得分:6)
另一个好处是,通过这样做,SQL查询计划被编译,缓存和重用。如果对查询的调用量很小,这不是什么大问题,但如果你有很多,那么这样做确实有一些显着的性能优势。
答案 2 :(得分:4)
根据我自己的经验:性能提升非常重要。前段时间我在一个项目上工作,我们使用自己的对象关系映射。我们利用庞大的数据库作为复杂对象模型的持久存储 - 具有按需对象加载和弱引用对象生命周期。
使用准备好的命令对于该应用程序的成功至关重要,因为它单独使系统实际可用。
换句话说:如果执行许多SQL命令 - 它们完全相同或仅在参数值上有所不同 - ,您将看到巨大的性能提升。
我没有确切的数字或链接,但我可以证明自己的经验。
答案 3 :(得分:-1)
根据IDbCommand.Prepare Method documentation:
服务器会根据需要自动缓存重用计划; 因此,无需直接在您的方法中调用此方法 客户申请。
我还发现了这个Databases Administrators answer,其中提供了有关prepare
方法的大量详细信息以及为什么我没有取得任何重大改进。
关于SQL注入,您将受到保护,因为您使用了参数化的sqlCommand ...而不是因为您调用了prepare方法。