参数化查询

我是新的Visual C#,我对如何编写参数化查询感到困惑。 这是没有它们的代码,

using System; using System.Windows.Forms; using System.Data.SqlClient; namespace Insert_Data { public partial class Form1 : Form { private void button1_Click(object sender, EventArgs e) { SqlConnection con = new SqlConnection("Data Source=ZTABASSUM\\SQLEXPRESS01;Initial Catalog=IntroDataBase;Integrated Security=True"); con.Open(); SqlCommand sc = new SqlCommand("Insert into employee values ('"+ textBox1.Text +"' , " + textBox2.Text + ", '" + textBox3.Text + "', " + textBox4.Text + ", " + textBox5.Text + ");", con); int o = sc.ExecuteNonQuery(); MessageBox.Show(o + ":Record has been inserted"); con.Close(); } } } 

我不确定如何为每个文本框编写参数化查询。

我在代码中添加了注释以及之后的best practices

 // best practice - use meaningful method names private void buttonSaveEmployee_Click(object sender, EventArgs e) { // best practice - wrap all database connections in a using block so they are always closed & disposed even in the event of an Exception // best practice - retrieve the connection string by name from the app.config or web.config (depending on the application type) (note, this requires an assembly reference to System.configuration) using(SqlConnection con = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyConnectionName"].ConnectionString)) { // best practice - use column names in your INSERT statement so you are not dependent on the sql schema column order // best practice - always use parameters to avoid sql injection attacks and errors if malformed text is used like including a single quote which is the sql equivalent of escaping or starting a string (varchar/nvarchar) // best practice - give your parameters meaningful names just like you do variables in your code SqlCommand sc = new SqlCommand("INSERT INTO employee (FirstName, LastName, DateOfBirth /*etc*/) VALUES (@firstName, @lastName, @dateOfBirth /*etc*/)", con); // best practice - always specify the database data type of the column you are using // best practice - check for valid values in your code and/or use a database constraint, if inserting NULL then use System.DbNull.Value sc.Parameters.Add(new SqlParameter("@firstName", SqlDbType.VarChar, 200){Value = string.IsNullOrEmpty(textBoxFirstName.Text) ? (object) System.DBNull.Value : (object) textBoxFirstName.Text}); sc.Parameters.Add(new SqlParameter("@lastName", SqlDbType.VarChar, 200){Value = string.IsNullOrEmpty(textBoxLastName.Text) ? (object) System.DBNull.Value : (object) textBoxLastName.Text}); // best practice - always use the correct types when specifying your parameters, in this case a string is converted to a DateTime type before being assigned to the SqlParameter.Value // note - this is not a very robust way to parse a date as the user is never notified in the event of failure, the purpose here is simply to show how to use parameters of various types DateTime dob; sc.Parameters.Add(new SqlParameter("@dateOfBirth", SqlDbType.Date){Value = DateTime.TryParse(textBoxDateOfBirth.Text, out dob) ? (object) dob : (object) System.DBNull.Value}); // best practice - open your connection as late as possible unless you need to verify that the database connection is valid and wont fail and the proceeding code execution takes a long time (not the case here) con.Open(); int o = sc.ExecuteNonQuery(); MessageBox.Show(o + ":Record has been inserted"); // the end of the using block will close and dispose the SqlConnection // best practice - end the using block as soon as possible to release the database connection } } 

使用ADO.NET的最佳实践回顾

  • 将所有数据库连接包装在一个使用块中,这样即使出现exception,它们也会一直关闭和处理。 有关使用语句的更多信息,请参阅使用Statement(C#参考)
  • 从app.config或web.config按名称检索连接字符串(取决于应用程序类型)
    • 这需要对System.configuration的程序集引用
    • 有关如何构造配置文件的其他信息,请参阅连接字符串和配置文件
  • 始终使用传入值的参数
    • 避免sql注入攻击
    • 如果使用格式错误的文本,例如包含单引号,即sql等效于转义或启动字符串(varchar / nvarchar),则避免错误
    • 让数据库提供程序重用查询计划(不受所有数据库提供程序支持),从而提高效率
  • 使用参数时
    • 为您的Sql参数提供有意义的名称,就像在代码中执行变量一样
    • 指定正在使用的列的数据库数据类型,这可确保不使用可能导致意外结果的错误参数类型
    • 在将传入参数传递给命令之前validation传入参数,垃圾输出中有一个名为garbage的表达式。 尽可能早地在堆栈中validation传入值
    • 在分配参数值时使用正确的类型,例如:不要分配DateTime的字符串值,而是将实际的DateTime实例分配给参数的值
    • 不要使用方法AddWithValue ,主要原因是在需要时很容易忘记指定参数类型或精度/比例。 有关其他信息,请参阅我们是否已停止使用AddWithValue?
  • 使用数据库连接时
    • 尽可能晚地打开连接并尽快关闭。 这是使用任何外部资源时的一般准则
    • 永远不要共享数据库连接(例如:让单一主机具有共享数据库连接)。 让代码在需要时始终创建一个新的数据库连接实例,然后让调用代码处理它并在完成后“抛弃它”。 原因是
      1. 大多数数据库提供程序都有某种连接池,因此在托管代码中这样做非常便宜
      2. 如果代码开始使用多个线程,它将消除任何未来的错误

您应该在SQL命令对象上使用create parameter方法

将SQL命令中的字符串更改为

"Insert into employee values (@Employee1,@Employee2,@Employee3,@Employee4,@Employee5);"

然后在执行查询之前添加参数:

 sc.Parameters.AddRange(new[]{ new SqlParameter("@Employee1",SqlDbType.VarChar,255){ Value= textBox1.Text}, new SqlParameter("@Employee2",SqlDbType.VarChar,255){ Value= textBox2.Text}, new SqlParameter("@Employee3",SqlDbType.VarChar,255){ Value= textBox3.Text}, new SqlParameter("@Employee4",SqlDbType.VarChar,255){ Value= textBox4.Text}, new SqlParameter("@Employee5",SqlDbType.VarChar,255){ Value= textBox5.Text} }); 

注意:这假设您的SQL变量的类型将是VARCHAR ,大小将是255 ,有关正在使用的方法和正在使用的SqlParameter构造函数的更多信息,请查看MSDN以获取更多文档。

  • SqlParameterCollection.AddRange方法(SqlParameter [])
  • SqlParameter构造函数(String,SqlDbType,Int32)

参数化查询用于避免sql注入。 直接包含非参数(数据)的查询称为参数化查询。 通过使用这个我们可以避免SQL注入(一种类型的黑客攻击)。

c#中参数化查询的示例

  string strQuery; SqlCommand cmd; strQuery = "insert into customers (CustomerID, CompanyName) values(@CustomerID, @CompanyName)"; cmd = new SqlCommand(strQuery); cmd.Parameters.AddWithValue("@CustomerID", "A234"); cmd.Parameters.AddWithValue("@CompanyName", "DCB"); String strConnString = system.Configuration.ConfigurationManager.ConnectionStrings["conString"].ConnectionString; SqlConnection con = new SqlConnection(strConnString); cmd.CommandType = CommandType.Text; cmd.Connection = con; try { con.Open(); cmd.ExecuteNonQuery(); return true; } catch (Exception ex) { Response.Write(ex.Message); return false; } finally { con.Close(); con.Dispose(); } 

..

同样你也可以用于选择查询..

供参考,请参阅此链接

如果您有数据库上下文,可以这样做:

 int rowsAffected = context. ExecuteStoreCommand("Insert into employee values ({0}, {1}, {2}, {3}, {4})", textBox1.Text, textBox2.Text, textBox3.Text, textBox4.Text, textBox5.Text); MessageBox.Show(rowsAffected + ":Record has been inserted");\ 

cf https://msdn.microsoft.com/en-us/library/ee358769%28v=vs.100%29.aspx

请停止使用AddWithValue,因为它推断数据库类型(坏),在我看来也不是干净的代码

这里有一些简单的代码可以帮助您入门。

 OracleConnection connection = GetConnection(); OracleCommand command = connection.CreateCommand(); command.CommandText = procedure; command.CommandType = CommandType.StoredProcedure; command.Parameters.Add("INID", OracleDbType.Int32).Value = person.PersonID; command.Parameters.Add("REFCURSOR", OracleDbType.RefCursor).Direction = ParameterDirection.Output; 

不要介意它是Oracle,同样的原则适用于SQL。