最近在学习用C#进行数据库相关操作,并在此进行了记录,参考的书本是C#从入门到精通,持续更改中......
1.用Connection对象连接数据库
1.1 连接对象
使用的数据库不同,引入不同的命名空间,然后通过命名空间中的Connection对象连接类连接数据库。主要包括以下几种访问数据库的对象类:SQL Server、MySQL、Odbc、OleDb、OracleClient,本文使用连接SQL Server,首先通过以下命令引用SQL Server数据提供程序
SQL Server
using System.Data.SqlClient;
1.2 数据库的连接、断开
调用SqlCommection对象的Open()方法打开数据库,通过SqlCommection对象的State属性判断数据库的连接状态。调用SqlCommection对象的Close()方法、Dispose()方法实现与数据库断开连接,并释放占用的资源。
新建一个项目
添加控件如下,”连接“按钮承担与数据库连接和断开的功能,代码如下:
//声明一个 连接数据库的字符串,
string Constr;
//创建一个SqlConnection对象
SqlConnection sqlconn;
//创建一个bool 表示数据库连接状态
private bool connnstate = false;
/// <summary>
/// 数据库连接 断开
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_connect_Click(object sender, EventArgs e)
{
try
{
if(connnstate==false)
{//未连接
if(tb_dbname.Text == "")
{
MessageBox.Show("数据库名称不能为空");
}
else
{
// string Constr = "server=服务器名称;database=数据库名称";uid=登录名;pwd=密码";
Constr = "server=LAPTOP-DL9AITB5;database=" + tb_dbname.Text.Trim() + ";uid=sa;pwd=123456";
sqlconn = new SqlConnection(Constr);
sqlconn.Open();
if (sqlconn.State == ConnectionState.Open)
{ //处于连接状态时
connnstate = true;
tb_state.Text = "数据库已经连接!";
btn_connect.Text = "断开";
}
}
}
else
{ //已连接
if (tb_dbname.Text == "")
{
MessageBox.Show("数据库名称不能为空");
}
else
{
Constr = "server=LAPTOP-DL9AITB5;database=" + tb_dbname.Text.Trim() + ";uid=sa;pwd=123456";
sqlconn = new SqlConnection(Constr);
sqlconn.Close();
sqlconn.Dispose();
if (sqlconn.State == ConnectionState.Closed)
{ //处于连接状态时
connnstate = false;
tb_state.Text = "数据库已经断开!";
btn_connect.Text = "连接";
}
}
}
}
catch (Exception ex)
{
MessageBox.Show("出现异常!\r" + ex.Message);
}
}
结果:
2.用Command对象执行SQL语句
Command对象是数据命令对象,功能:向数据库发送查询、更新、删除、添加操作的SQL语句。
2.1 设置数据源类型
Command对象最常用的三个属性,Connection、CommandText、CommandType。
Connection属性:设置SQL命令的使用对象:SqlConnection;
CommandText:设置对数据源执行的SQL语句或存储过程;
CommandType:指定CommandText的类型。
2.2 执行SQL
调用Command对象的ExecuteNonQuery()方法,执行发送的SQL语句;
调用Command对象的ExecuteReader()方法,执行SQL语句,获取数据表中指定字段所对应的数据;
调用Command对象的ExecuteScalar()方法,得到指定数据表的数据数量
3.ADO.NET中的数据容器
3.1 DataSet
DataSet是一个独立的数据库独立性对象,它包含一个或多个DataTable对象,以及这些表之间的关系。
它是一个内存中的对象,可以看作是一个小型数据库,具有独立的schema,可以在不同的应用程序之间传输数据。
DataSet支持XML数据交换,可以通过XmlSerializer序列化到XML,或者从XML反序列化回来。
DataSet支持事务,可以对多个表进行原子性操作。
DataSet提供了数据的完整性和一致性,可以通过约束和参照完整性来保证。
3.2 DataTable
DataTable是DataSet中的一个对象,可以看作是DataSet中的一个表。
它包含行和列,每行表示一条记录,每列表示一个字段。
DataTable可以与数据库表结构相对应,通常用于存储数据。
DataTable提供了数据的完整性和一致性,可以通过约束和参照完整性来保证。
3.3 DataReader:
DataReader是一个只读的数据容器,用于从数据库中读取数据。
它提供了一种高效的方式来读取大量数据,因为它是基于流的方式来读取数据的,一次读取一行。
DataReader不支持事务操作,因为它是一次性读取所有数据。
DataReader不支持XML数据交换,因为它是一次性读取所有数据。
DataAdapter:
DataAdapter是一个桥梁,用于在DataSet和数据库之间传输数据。
它可以填充DataSet,也可以更新数据库中的数据。
DataAdapter支持事务操作,可以对多个表进行原子性操作。
DataAdapter支持XML数据交换,可以通过XmlSerializer序列化到XML,或者从XML反序列化回来。
3.4 DataAdapter
DataAdapter是一个桥梁,用于在DataSet和数据库之间传输数据。
它可以填充DataSet,也可以更新数据库中的数据。
DataAdapter支持事务操作,可以对多个表进行原子性操作。
DataAdapter支持XML数据交换,可以通过XmlSerializer序列化到XML,或者从XML反序列化回来。
总结:
DataSet和DataTable都是用于存储数据的,DataSet是包含多个DataTable的容器,而DataTable是DataSet中的单个表。
DataReader用于高效读取大量数据,是一次性读取所有数据。
DataAdapter用于在DataSet和数据库之间传输数据,支持事务操作和XML数据交换。
4.数据库数据的查询、插入、删除和更新
DataAdapter对象通过相关属性向数据库发送SQL语句,实现查询、删除、插入、更新等功能,实现与数据源之间的互通。
SelectCommand属性:查询;
DeleteCommand属性:删除;
InsertCommand属性:插入;
UpdataCommand属性:更新。
4.1 检索数据源中的数据
调用DataAdapter对象的Fill()方法填充DataSet数据集,Fill方法使用SELECT语句检索数据。
窗体设计如下:
实现程序如下
private void btn_jiazai_Click(object sender, EventArgs e)
{
if (connnstate==false)
{
MessageBox.Show("数据库未连接!");
}
else
{
try
{
jiazaiData();
}
catch(Exception ex)
{
MessageBox.Show("加载失败!"+ex.Message);
}
}
}
private void jiazaiData()
{
//创建一个SqlCommand对象
// SqlCommand sqlcmd = new SqlCommand("select * from 表格名称",sqlconn);
sqlcmd = new SqlCommand("select * from " + tb_tbName.Text.Trim(), sqlconn);
//创建一个SqlDataAdapter对象
sda = new SqlDataAdapter();
//将其SelectCommand属性设置为cmd
sda.SelectCommand = sqlcmd;
//创建了一个新的DataSet对象,这是一个内存中的数据库,可以容纳多个数据表
ds = new DataSet();
sda.Fill(ds, "cs");
//将DataSet对象中的第一个数据表(索引为0)设置为dataGridView1控件的数据源
dGV_1.DataSource = ds.Tables[0];
//因为第一列为键值,所以将此改为已读
dGV_1.Columns[0].ReadOnly = true;
}
其中,创建DateSet对象,可以理解为创建了一个虚拟数据库,用以保存所连接数据库中的将要处理数据表中的数据
结果
数据库表数据:
注意:表格名称不要出现错误,要保证数据库中存在!
上一方式是分了两个步骤(先连接数据库,再加载表格数据),如果用按钮直接连接数据库并打开指定鼠标表,代码如下
//创建一个SqlConnection对象
SqlConnection sqlconn;
//创建一个SqlDataAdapter对象
SqlDataAdapter sda;
/// <summary>
/// 直接连接数据库并加载数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <summary>
/// 直接连接数据库并加载数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_jiazai2_Click(object sender, EventArgs e)
{
try
{
Constr = "server=LAPTOP-DL9AITB5;database=" + tb_dbname.Text.Trim() + ";uid=sa;pwd=123456";
sqlconn = new SqlConnection(Constr);
sqlconn.Open();
sqlcmd = new SqlCommand("select * from " + tb_tbname2.Text.Trim(), sqlconn);
sda = new SqlDataAdapter();
sda.SelectCommand = sqlcmd;
ds = new DataSet();
sda.Fill(ds, "cs");
dGV_2.DataSource = ds.Tables[0];
dGV_2.Columns[0].ReadOnly = true;
}
catch(Exception ex)
{
MessageBox.Show("异常!" + ex);
}
}
网上查看的代码一般都是打开数据库和关闭数据库一起出现,操作完之后即刻关闭,此做法本人还没有理解很到位, 但是为了确保在使用完数据库连接后,无论由于何种原因(比如异常)导致没有正常关闭连接,都能正确地关闭连接并释放资源,以维护系统的稳定性和资源的有效管理。添加了一个窗口关闭事件:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if(sqlconn.State==ConnectionState.Open)
{
sqlconn.Close();
sqlconn.Dispose();
}
}
4.2 单条数据更新
使用DataAdapter对象的Update()方法,可以将DataSet中修改后的数据更新到数据库中。
注意:使用Update()方法,必须保证数据表中有主键,不然会出现异常。
此处实现的是修改单条数据
窗口设计
实现思路:加载数据表数据在DataGridView中显示,单击某条数据后,信息显示在对应的TextBox中(根据数据表表头,自己放置TextBox)。在响应TextBox中修改信息,然后单击修改按钮,通过Update方法更新数据源,删除操作同理;执行插入按钮时,填写各个TextBox,加入条件ID不能重复,然后通过Update方法更新数据源。
1.需要添加一个DataGridView点击事件,使其显示单击的某条数据详细信息
设置DataGridView属性,不然会报错
ReadOnly=true;禁止编辑DataGridView
SelectionMode=FullRowSelect;使控件能够整行选择
private void dGV_1_CellClick(object sender, DataGridViewCellEventArgs e)
{
textID.Text = dGV_1.SelectedCells[0].Value.ToString();
textName.Text = dGV_1.SelectedCells[1].Value.ToString();
textPass.Text = dGV_1.SelectedCells[2].Value.ToString();
}
效果
2.修改
private void btn_update_Click(object sender, EventArgs e)
{
//单条数据修改
if(connnstate==false)
{
MessageBox.Show("数据库未连接!");
}
else
{
// 从某个DataSet对象ds中获取一个名为"cs"的DataTable
DataTable dt = ds.Tables["cs"];
//调用SqlDataAdapter对象的FillSchema方法,填充DataTable的架构信息
sda.FillSchema(dt, SchemaType.Mapped);
//通过DataTable的Rows集合找到一个与txtNo控件中文本内容相匹配的DataRow。
DataRow dr = dt.Rows.Find(textID.Text);//主键
//设置DataRow中的值 为textBox中的内容
dr["Name"] = this.textName.Text.Trim();
dr["Pass"] = this.textPass.Text.Trim();
//SqlCommandBuilder对象用于生成与SqlDataAdapter关联的更新命令,将DataSet中的变化反映到数据库中。
SqlCommandBuilder cmdbuider = new SqlCommandBuilder(sda);
//更新数据源数据
sda.Update(dt);
}
}
将2 大二 222改为 大三 3333 结果
4.3 单条数据删除、插入
遇到的问题:操作前的数据依然在DataGridView中显示
解决:加载的数据前重新创建一个新的DataSet对象,这样每次加载的数据源都是新数据(前文加载加载数据按钮代码已更改)
(1)删除
private void btn_delete_Click(object sender, EventArgs e)
{
//定义删除数据的SQL语句
// string strsql = "delete from tb_PDic where ID=2";
string strsql = "delete from " + tb_tbName.Text.Trim() + " where ID=" + textID.Text.Trim();
try
{
if(connnstate != false)
{
//防止误操作,添加一个弹窗
DialogResult dr = MessageBox.Show("确定删除?", "服务器信息", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (dr == DialogResult.Yes)
{
SqlCommand sqlcmd = new SqlCommand(strsql, sqlconn); //创建SqlCommand对象
//判断ExecuteNonQuery方法返回的参数是否大于0,大于0表示删除成功
if (Convert.ToInt32(sqlcmd.ExecuteNonQuery()) > 0)
{
MessageBox.Show("删除成功!");
jiazaiData();
}
else
{
MessageBox.Show("删除失败!不存在该条记录!!!");
}
}
else
{
return;
}
}
else
{
MessageBox.Show("数据库未连接");
}
}
catch(Exception ex)
{
MessageBox.Show("操作失败"+ex);
}
}
结果
(2)插入
窗口设计
private void btn_insert_Click(object sender, EventArgs e)
{
string strsql2 = "INSERT INTO " + tb_tbName.Text.Trim() + " VALUES('" + addID.Text.Trim() + "','" + addName.Text.Trim() + "','" + addCode.Text.Trim() + "');";
if (connnstate == true)
{
try
{
SqlCommand sqlcmd = new SqlCommand(strsql2, sqlconn); //创建SqlCommand对象
//判断ExecuteNonQuery方法返回的参数是否大于0,大于0表示操作成功
if (Convert.ToInt32(sqlcmd.ExecuteNonQuery()) > 0)
{
//MessageBox.Show("插入成功!");
jiazaiData();
addID.Text = "";
addName.Text = "";
addCode.Text = "";
}
else
{
MessageBox.Show("失败!");
}
}
catch (Exception ex)
{
MessageBox.Show("失败!" + ex.Message);
}
}
else
{
MessageBox.Show("数据库未连接");
}
}
结果
4.4 批量更新数据
直接在DataGridView控件中修改数据:用 DataTable的ImportRow()方法、将更改后的数据复制到一个DataTable中,再用DataAdapter对象的Update()方法更新到数据库中。
DataGridView属性设置:
单元格、列、行和控件ReadOnly属性都设置为false;
步骤:1.加载数据到DataGridView中显示,更改数据;2.选中某行已更改的数据,点击“更新”按钮,将该行的变化更新到数据库中(注意:更新到数据库的是选中单元格所在行的数据,无法一次性更新多行,更新不同行数据需要多次选中-更新)
/// <summary>
/// 批量修改事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void bt_piliangUpdate_Click(object sender, EventArgs e)
{
if(Update()==true)
{
MessageBox.Show("修改成功");
}
}
/// <summary>
/// 修改方法(bool) 更新完毕则为true
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
SqlDataAdapter adapter;//声明一个SqlDataAdapter变量
private new Boolean Update()
{
bool update = false;
string strSql = "select * from tb_Login";
DataTable dtUpdate = new DataTable();//用来存储所选表格更新后的数据
dtUpdate = this.dbconn(strSql);
DataTable dtShow = new DataTable();//用来存储数据源数据
dtShow = (DataTable)this.dGV_2.DataSource;
dtUpdate.ImportRow(dtShow.Rows[intindex]);//将dtShow中指定行的数据导入到dtUpdate中
try
{
SqlCommandBuilder CommandBuiler;
CommandBuiler = new SqlCommandBuilder(this.adapter);//创建一个新的SqlCommandBuilder对象,与sda关联。
this.adapter.Update(dtUpdate);//使用Update方法将dtUpdate中的更改应用到数据库。
dtUpdate.AcceptChanges();
update = true;
}
catch (Exception ex)
{
MessageBox.Show("未发现有变化\r" + ex);
}
return update;
}
/// <summary>
/// DataTable类型的表格填充方法
/// </summary>
/// <param name="strSql"></param>
/// <returns></returns>
private DataTable dbconn(string strsql)
{
DataTable dtSelect = new DataTable();//创建一个新的DataTable对象来存储查询结果。
if (sqlconn.State == ConnectionState.Open)
{
this.adapter = new SqlDataAdapter(strsql, sqlconn);//创建一个新的SqlDataAdapter对象,它用于执行SQL命令并填充DataTable
int rnt = this.adapter.Fill(dtSelect);//使用Fill方法将查询结果填充到dtSelect表中。
}
else
{
MessageBox.Show("数据库未连接");
}
return dtSelect;//方法返回填充好的DataTable
}
int intindex = 0;
/// <summary>
/// 点击任何单元格时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void dGV_2_CellClick(object sender, DataGridViewCellEventArgs e)
{
// 获取被点击的行的索引
intindex = e.RowIndex;
}
过程演示
1.加载数据
2.在DataGridView中更改数据
3.按行更新
选中1---->更新
选中3----->更新
选中6----->更新
由数据库结果可见,2并没选中更新过,所以数据源中的数据未改变。