我是 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 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 的最佳实践回顾
- 将所有数据库连接包装在一个 using block 中,这样即使出现异常,它们也始终会被关闭和处理。参见 using Statement (C# Reference)有关使用语句的更多信息
- 从 app.config 或 web.config 中按名称检索连接字符串(取决于应用程序类型)
- 这需要对
System.configuration
的程序集引用 - 参见 Connection Strings and Configuration Files有关如何构建配置文件的更多信息
- 这需要对
- 始终使用传入值的参数
- 避免sql injection攻击
- 如果使用格式错误的文本(例如包含单引号,这是转义或开始字符串(varchar/nvarchar)的 sql 等价物),请避免错误
- 让数据库提供者重用查询计划(并非所有数据库提供者都支持)以提高效率
- 使用参数时
- 为您的 Sql 参数赋予有意义的名称,就像您在代码中为变量命名一样
- 指定您正在使用的列的数据库数据类型,这确保不会使用可能导致意外结果的错误参数类型
- 在将传入参数传递到命令之前验证传入参数,有一个表达式称为垃圾输出中的垃圾。尽早在堆栈中验证传入值
- 在分配参数值时使用正确的类型,例如:不要分配 DateTime 的字符串值,而是将实际的 DateTime 实例分配给参数值
- 不要使用方法 AddWithValue ,主要原因是很容易忘记在需要时指定参数类型或精度/比例。有关其他信息,请参阅 Can we stop using AddWithValue already?
- 使用数据库连接时
- 尽可能晚地打开连接并尽快关闭它。这是使用任何外部资源时的一般准则
- 切勿共享数据库连接(例如:让单例主机共享数据库连接)。让您的代码始终在需要时创建一个新的数据库连接实例,然后让调用代码处理它并在完成后“丢弃它”。这样做的原因是
- 大多数数据库提供商都有某种连接池,因此在托管代码中这样做非常便宜
- 如果代码开始使用多线程,它会消除任何 future 的错误
关于c# - 参数化查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38574826/