了解ADO.NET
什么是ADO.NET呢?其实ADO.NET就是C#应用程序访问数据库的一个中间组件。
那ADO.NET又是由哪些部分组成呢?来看下面这张图
根据上面的图,来捋一遍数据库CRUD的流程:
连接数据库 >>> SqlCommand对数据库进行操作 >>>
查询出的数据放到DataSet中(若是增删改只是返回受影响记录条数,即返回int) >>> 关闭数据库
ADO.NET操作实例
准备工作:准备一张表,4个字段,10条测试记录;准备一个winForm,如图所示
接下来我们开始写代码,先写个查询
private void btn_query_Click(object sender, EventArgs e)
{
using(SqlConnection conn = new SqlConnection("Data Source=DESKTOP-2HL1HGR\\SQL2014;Initial Catalog=TestDemo;Integrated Security=True"))
{
//打开数据库连接
conn.Open();
//查询的sql语句
string sql = "SELECT * FROM Student";
//创建命令对象
SqlCommand cmd = new SqlCommand(sql, conn);
//执行查询返回的结果集
SqlDataReader sdr = cmd.ExecuteReader();
//每次查询前先清空textbox中原来的数据
textBox1.Text = "";
//显示标题
textBox1.Text += "序号\t姓名\t年龄\t爱好\r\n\r\n";
//如果结果集存在数据,则读取一行,不存在则sdr.Read()返回false
while (sdr.Read())
{
textBox1.Text += sdr["F_id"].ToString() + "\t" + sdr["F_name"].ToString() + "\t" + sdr["F_age"].ToString() + "\t" + sdr["F_hobby"].ToString() + "\r\n";
}
}
}
结果如下
增加数据,由于此次只针对ADO.NET进行研究,所以为图方便我把增加的数据写死了。
private void btn_insert_Click(object sender, EventArgs e)
{
using(SqlConnection conn = new SqlConnection("Data Source=DESKTOP-2HL1HGR\\SQL2014;Initial Catalog=TestDemo;Integrated Security=True"))
{
conn.Open();
string sql = "INSERT INTO Student (F_name, F_age, F_hobby) VALUES ('小红', 20, '跳绳')";
SqlCommand cmd = new SqlCommand(sql, conn);
//返回受影响的行数
int rows = cmd.ExecuteNonQuery();
//如果受影响行数大于0,证明sql执行成功
if (rows > 0)
MessageBox.Show("新增成功!");
else
MessageBox.Show("新增失败!");
}
}
执行结果:
修改数据
private void btn_edit_Click(object sender, EventArgs e)
{
using(SqlConnection conn = new SqlConnection("Data Source=DESKTOP-2HL1HGR\\SQL2014;Initial Catalog=TestDemo;Integrated Security=True"))
{
conn.Open();
string sql = "UPDATE Student SET F_name = '小强' WHERE F_Id = 4";
SqlCommand cmd = new SqlCommand(sql, conn);
int rows = cmd.ExecuteNonQuery();
if (rows > 0)
MessageBox.Show("修改成功!");
else
MessageBox.Show("修改失败!");
}
}
执行结果
删除数据
private void btn_delete_Click(object sender, EventArgs e)
{
using(SqlConnection conn = new SqlConnection("Data Source=DESKTOP-2HL1HGR\\SQL2014;Initial Catalog=TestDemo;Integrated Security=True"))
{
conn.Open();
string sql = "DELETE FROM Student WHERE F_Id = 4";
SqlCommand cmd = new SqlCommand(sql, conn);
int rows = cmd.ExecuteNonQuery();
if (rows > 0)
MessageBox.Show("删除成功!");
else
MessageBox.Show("删除失败!");
}
}
执行结果
ExecuteNonQuery()
返回受影响的行数,写法:
int rows = cmd.ExecuteNonQuery();
细心的同学可能发现了,增删改这3个方法执行起来一样的操作,无非是sql语句的变化而已,而在SqlCommand中基本就是用ExecuteNonQuery()方法,返回的是受影响的行数。
那么在增删改查这4个操作中最复杂的就是查询了。因为查询可能会返回一张表,一条记录,多条记录,单个值等等,所以
在SqlCommand中对于查询有多个方法可以使用,下面我就来讲解一下2种查询命令。
ExecuteReader()
返回的是一个结果集
这就是上面第一个查询用到的方法,通过游标把结果集的数据依次读出,写法:
SqlDataReader sdr = cmd.ExecuteReader();
while(sdr.Read()){
//读出的数据,格式例:sdr[0] 或 sdr["F_name"]
}
代码在上面已经写过,就不再重复写了。
ExecuteScalar()
返回第一行第一列的值
一般用于计数,写法:
Object count = cmd.ExecuteScalar();
观察以下代码,功能为从数据库取出记录数显示
private void btn_count_Click(object sender, EventArgs e)
{
using(SqlConnection conn = new SqlConnection("Data Source=DESKTOP-2HL1HGR\\SQL2014;Initial Catalog=TestDemo;Integrated Security=True"))
{
conn.Open();
string sql = "SELECT COUNT(*) FROM Student";
SqlCommand cmd = new SqlCommand(sql, conn);
Object count = cmd.ExecuteScalar();
textBox1.Text = "记录数" + count.ToString();
}
}
执行结果
思考:上述代码的缺陷
虽然以上的代码可以非常嗨皮地解决所有与数据库交互的问题,但是我们发现代码的冗余非常的大。
首先我们一直在写一句话using(SqlConnection…),其次我们也一直在打开数据库,还一直在实例化SqlCommand对象,其实这些代码都是重复的,我们不想去在重复的代码上浪费太多时间,所以我们把这些重复代码都抽象出来,SqlHelper就出现了。
SqlHelper
于是乎,我们新建一个抽象类SqlHelper来满足我们的需求
public abstract class SqlHelper
{
//连接字符串
public static readonly string connString = "Data Source=DESKTOP-2HL1HGR\\SQL2014;Initial Catalog=TestDemo;Integrated Security=True";
//执行增删改方法
public static int ExecteNonQuery(string sql)
{
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
int rows = cmd.ExecuteNonQuery();
return rows;
}
}
//返回一个DataSet的查询方法
public static DataSet ExecuteDataSet(string sql)
{
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
//表示用于填充 DataSet 和更新 SQL Server 数据库的一组数据命令和一个数据库连接
SqlDataAdapter sda = new SqlDataAdapter();
//表示数据在内存中的缓存
DataSet ds = new DataSet();
sda.SelectCommand = cmd;
sda.Fill(ds);
return ds;
}
}
//返回第一行第一列数据的查询方法
public static Object ExecuteScalar(string sql)
{
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
Object result = cmd.ExecuteScalar();
return result;
}
}
}
此SqlHelper是我自己写的,目的只是为了给我前面写的方法做一个简单的抽象,而你们平常看到的SqlHelper可能会略有不同,只是根据不同的情况下判断了更多条件而已,理解SqlHelper的原理后可以自行扩充。
重写CRUD方法
我们写好了SqlHelper,那么现在开始重写我们的CRUD方法
首先重写增删改的方法
// 新增一条记录
private void btn_insert_Click(object sender, EventArgs e)
{
string sql = "INSERT INTO Student (F_name, F_age, F_hobby) VALUES ('小红', 20, '跳绳')";
int rows = SqlHelper.ExecteNonQuery(sql);
if (rows > 0)
MessageBox.Show("新增成功!");
else
MessageBox.Show("新增失败!");
}
// 修改一条记录
private void btn_edit_Click(object sender, EventArgs e)
{
string sql = "UPDATE Student SET F_name = '小强' WHERE F_Id = 4";
int rows = SqlHelper.ExecteNonQuery(sql);
if (rows > 0)
MessageBox.Show("修改成功!");
else
MessageBox.Show("修改失败!");
}
// 删除一条记录
private void btn_delete_Click(object sender, EventArgs e)
{
string sql = "DELETE FROM Student WHERE F_Id = 4";
int rows = SqlHelper.ExecteNonQuery(sql);
if (rows > 0)
MessageBox.Show("删除成功!");
else
MessageBox.Show("删除失败!");
}
感受到代码的简洁性了吗?真正需要用到的代码不过2行,就可以执行完增删改的操作了。
重写查询操作
private void btn_query_Click(object sender, EventArgs e)
{
string sql = "SELECT * FROM Student";
DataSet ds = SqlHelper.ExecuteDataSet(sql);
//取到DataSet中的第一张表
DataTable dt = ds.Tables[0];
textBox1.Text = "";
textBox1.Text += "序号\t姓名\t年龄\t爱好\r\n\r\n";
//遍历DataTable中的所有行
foreach (DataRow dr in dt.Rows)
{
textBox1.Text += dr["F_id"] + "\t" + dr["F_name"] + "\t" + dr["F_age"] + "\t" + dr["F_hobby"] + "\r\n";
}
}
首先要捋清楚一个概念,DataSet是DataTable的集合,DataTable是DataRow的集合。
其中DataSet是表的集合,DataTable是一张表,DataRow是表中的一行数据。
一般来说,我们最多只需要取到数据库中的一张表就可以了。
所以上述代码的意思是,取到DataSet中的第一张表,再遍历表中所有行并且打印至TextBox1,是不是也没什么难度?
执行结果都一样,所以就不再贴图了。
ADO.NET与实体类的映射
一般来说,正规开发一定会用实体类来临时存储数据,我们在程序中可以把实体类作为参数传递,更加方便。
首先定义一个Student实体类
public class Student
{
public int F_id { get; set; }
public string F_name { get; set; }
public int F_age { get; set; }
public string F_hobby { get; set; }
}
既然这写到这里我们不妨把数据改成动态的,不把他写死了。界面如图所示:
然后我们这么来改代码
/// <summary>
/// 查询Student表中的所有数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_query_Click(object sender, EventArgs e)
{
string sql = "SELECT * FROM Student";
DataSet ds = SqlHelper.ExecuteDataSet(sql);
DataTable dt = ds.Tables[0];
List<Student> list = new List<Student>();
foreach (DataRow dr in dt.Rows)
{
Student stu = new Student();
stu.F_id = Int32.Parse(dr["F_id"].ToString());
stu.F_name = dr["F_name"].ToString();
stu.F_age = Int32.Parse(dr["F_age"].ToString());
stu.F_hobby = dr["F_hobby"].ToString();
list.Add(stu);
}
textBox1.Text = "";
textBox1.Text += "序号\t姓名\t年龄\t爱好\r\n\r\n";
foreach(Student stu in list)
{
textBox1.Text += stu.F_id + "\t" + stu.F_name + "\t" + stu.F_age + "\t" + stu.F_hobby + "\r\n";
}
}
/// <summary>
/// 新增一条记录
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_insert_Click(object sender, EventArgs e)
{
Student stu = new Student();
stu.F_name = tb_name.Text;
stu.F_age = Int32.Parse(tb_age.Text);
stu.F_hobby = tb_hobby.Text;
string sql = string.Format("INSERT INTO Student (F_name, F_age, F_hobby) VALUES ('{0}', {1}, '{2}')", stu.F_name, stu.F_age, stu.F_hobby);
int rows = SqlHelper.ExecteNonQuery(sql);
if (rows > 0)
MessageBox.Show("新增成功!");
else
MessageBox.Show("新增失败!");
}
/// <summary>
/// 修改一条记录
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_edit_Click(object sender, EventArgs e)
{
Student stu = new Student();
stu.F_id = Int32.Parse(tb_id.Text);
stu.F_name = tb_name.Text;
stu.F_age = Int32.Parse(tb_age.Text);
stu.F_hobby = tb_hobby.Text;
string sql = string.Format("UPDATE Student SET F_name = '{0}', F_age = {1}, F_hobby = '{2}' WHERE F_Id = {3}", stu.F_name, stu.F_age, stu.F_hobby, stu.F_id);
int rows = SqlHelper.ExecteNonQuery(sql);
if (rows > 0)
MessageBox.Show("修改成功!");
else
MessageBox.Show("修改失败!");
}
/// <summary>
/// 删除一条记录
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_delete_Click(object sender, EventArgs e)
{
Student stu = new Student();
stu.F_id = Int32.Parse(tb_id.Text);
string sql = "DELETE FROM Student WHERE F_Id = " + stu.F_id;
int rows = SqlHelper.ExecteNonQuery(sql);
if (rows > 0)
MessageBox.Show("删除成功!");
else
MessageBox.Show("删除失败!");
}
如此便改完了我们的代码,此代码已测试可用,实现了ADO.NET与实体类的映射。
总结
实际上ADO.NET就只是一个与后台数据库交互的一种技术,本文从基础的写法到SqlHelper再到与实体的映射解释了ADO.NET的用法和使用途径,如有不足,欢迎指正。