[转载]C#中使用ADO.NET连接SQL Server数据库,自动增长字段用作主键,处理事务时的基本方法
问题描述:
假设在数据库中存在以下两张数据表:
User表,存放用户的基本信息,基本结构如下所示:
| 类型 | 说明 | |
| ID_User | int | 自动增长字段,用作该表的主键 |
| UserName | varchar |
UserDepart表,存放用户所拥有的部门(我们假设一个用户拥有多个部门,虽然听起来有点别扭,此处仅作示例,可以理解为一个用户拥有多个职位等等),该表的基本结构如下所示:
| 类型 | 说明 | |
| ID_UserDepart | int | 自动增长字段,用作该表的主键 |
| ID_User | int | 用户编号 |
| ID_Depart | int | 部门编号 |
向数据库中插入一条用户信息的时候,为了保证数据的一致性,必须使用事务的方式“同时”操作User表和UserDepart表。先将用户姓名写入User表中,再将其所拥有的部门写入UserDepart表中,使用事务机制保证这两步操作要么同时成功,要么同时失败。问题就出在:第一步操作完成后,我们并不知道该向第二步操作写入的ID_User的值是多少,因为这个值是SQL Server自动生成的。
解决思路:
可以借助 SELECT IDENT_CURRENT('User') AS ‘NewInsertID’ 来查询最近一次插入User表的数据的自动编号的值。
程序实现:
1 public struct Chaos_TranSQLCmd
2 {
3 /// <summary>
4 /// 一条SQL语句
5 /// </summary>
6 public string strSQL;
7
8 /// <summary>
9 /// 标记该条SQL语句是否需要连接ID_User
10 /// </summary>
11 public bool bNeedID;
12 }
13
14
15 public void Chaos_ExecuteSqlTran(List<Chaos_TranSQLCmd> listTranSQLCmd,string strInsertID_SQL)
16 {
17 using (SqlConnection ChaosSqlConn = new SqlConnection(strSqlConnString))
18 {
19 SqlCommand ChaosSqlCmd = new SqlCommand();
20 ChaosSqlCmd.Connection = ChaosSqlConn;
21 ChaosSqlConn.Open();
22 SqlTransaction ChaosSqlTran = ChaosSqlConn.BeginTransaction();
23 ChaosSqlCmd.Transaction = ChaosSqlTran;
24
25 try
26 {
27 string mID_User = "";
28
29 //先将数据插入User
30 ChaosSqlCmd.CommandText = strInsertID_SQL;
31 ChaosSqlCmd.ExecuteNonQuery();
32
33 //再获取ID_User
34 DataSet ds = this.ExecAdapter("select IDENT_CURRENT('PT_User') as 'ID'", "T");
35 DataTable dt = ds.Tables["T"];
36 if (dt.Rows.Count>0)
37 {
38 mID_User = dt.Rows[0]["ID"].ToString();
39 }
40
41 for (int i = 0; i < listTranSQLCmd.Count; i++)
42 {
43 //如果队列中的语句需要连接ID,则处理SQL语句后再执行
44 string strSQL = "";
45 if (listTranSQLCmd[i].bNeedID==true)
46 {
47 strSQL = string.Format(listTranSQLCmd[i].strSQL, mID_User);
48 }
49 else
50 {
51 strSQL = listTranSQLCmd[i].strSQL;
52 }
53
54 ChaosSqlCmd.CommandText = strSQL;
55 ChaosSqlCmd.ExecuteNonQuery();
56 }
57
58 //全部成功执行则提交
59 ChaosSqlTran.Commit();
60 }
61 catch (System.Data.SqlClient.SqlException Ex)
62 {
63 //发生问题则回滚
64 ChaosSqlTran.Rollback();
65 throw new Exception(Ex.Message);
66 }
67 }
68 }

测试代码如下:

1 static void Main(string[] args)
2 {
3 try
4 {
5 List<DB_Operation.ChaosDbOprt.Chaos_TranSQLCmd> Chaos_SQLCmdList = new List<DB_Operation.ChaosDbOprt.Chaos_TranSQLCmd>();
6
7 //构造SQL语句向User表中写入数据
8 string strSQL = "insert into PT_User (UserName) values ('Lee')";
9
10 //构造SQL语句向UserDepart表写入数据
11 for (int i = 0; i < 10; i++)
12 {
13 DB_Operation.ChaosDbOprt.Chaos_TranSQLCmd nCmd = new DB_Operation.ChaosDbOprt.Chaos_TranSQLCmd();
14 if (i==6)
15 {
16 //构造错误SQL语句,使写入数据库的操作不能成功执行
17 nCmd.strSQL = "insert into PT_UserDepart (ID_User,ID_Depart) values ({0}," + "A String which can't be inserted as ID_Depart)";
18 }
19 else
20 {
21 //正常SQL语句
22 nCmd.strSQL = "insert into PT_UserDepart (ID_User,ID_Depart) values ({0}," + i.ToString() + ")";
23 }
24 nCmd.bNeedID = true;
25 Chaos_SQLCmdList.Add(nCmd);
26 }
27
28 DB_Operation.ChaosDbOprt CDO = new DB_Operation.ChaosDbOprt();
29 CDO.Chaos_ExecuteSqlTran(Chaos_SQLCmdList, strSQL);
30
31 Console.WriteLine("数据写入成功!");
32 Console.ReadLine();
33 }
34 catch (Exception ex)
35 {
36 Console.WriteLine("Error:\r\n"+ex.Message);
37 Console.ReadLine();
38 }
39 }

规范化代码如下:

1 #region 实现数据库事务的方法,实现以事务的方式将多条SQL语句同时写入数据库(其中某些语句依赖于第一条语句插入数据库后自动生成的ID)
2
3 public struct Chaos_TranSQLCmd
4 {
5 /// <summary>
6 /// 一条SQL语句,在需要添加ID的地方用"{0}"来代替
7 /// 如:INSERT INTO PT_FeeItemDetails(ID_FeeItem,ID_ExamItem) VALUES ({0},005)等
8 /// </summary>
9 public string strSQL;
10
11 /// <summary>
12 /// 标记该条SQL语句是否需要连接ID
13 /// </summary>
14 public bool bNeedID;
15 }
16 /// <summary>
17 /// 该函数用于实现以事务的方式将多条SQL语句同时写入数据库(其中某些语句依赖于第一条语句插入数据库后自动生成的ID)
18 /// </summary>
19 /// <param name="strInsertID_SQL">需要先插入数据库中以产生ID的SQL语句</param>
20 /// <param name="strTableName">需要首先插入数据库中以产生ID的数据表的名称,如"PT_FeeItem"等</param>
21 /// <param name="listTranSQLCmd">需要连接ID的SQL语句的列表</param>
22 public void Chaos_ExecuteSqlTran_InsertID(string strInsertID_SQL,string strTableName, List<Chaos_TranSQLCmd> listTranSQLCmd)
23 {
24 using (SqlConnection ChaosSqlConn = new SqlConnection(strSqlConnString))
25 {
26 SqlCommand ChaosSqlCmd = new SqlCommand();
27 ChaosSqlCmd.Connection = ChaosSqlConn;
28 ChaosSqlConn.Open();
29 SqlTransaction ChaosSqlTran = ChaosSqlConn.BeginTransaction();
30 ChaosSqlCmd.Transaction = ChaosSqlTran;
31
32 try
33 {
34 string m_strID = "";
35
36 //先将数据插入User
37 ChaosSqlCmd.CommandText = strInsertID_SQL;
38 ChaosSqlCmd.ExecuteNonQuery();
39
40 string strSQL_Tmp = string.Format("SELECT IDENT_CURRENT('{0}') as 'ID'",strTableName);
41 //再获取ID
42 DataSet ds = this.ExecAdapter(strSQL_Tmp, "T");
43 DataTable dt = ds.Tables["T"];
44 if (dt.Rows.Count>0)
45 {
46 m_strID = dt.Rows[0]["ID"].ToString();
47
48 for (int i = 0; i < listTranSQLCmd.Count; i++)
49 {
50 //如果队列中的语句需要连接ID,则处理SQL语句后再执行
51 string strSQL = "";
52 if (listTranSQLCmd[i].bNeedID == true)
53 {
54 strSQL = string.Format(listTranSQLCmd[i].strSQL, m_strID);
55 }
56 else
57 {
58 strSQL = listTranSQLCmd[i].strSQL;
59 }
60
61 ChaosSqlCmd.CommandText = strSQL;
62 ChaosSqlCmd.ExecuteNonQuery();
63 }
64 }
65 else
66 {
67 //如果没有正确获取首先插入语句的ID,则回滚
68 ChaosSqlTran.Rollback();
69 throw new Exception("产生ID语句没有成功执行,后续语句无法继续执行,已回滚!\r\n");
70 }
71
72
73 //全部成功执行则提交
74 ChaosSqlTran.Commit();
75 }
76 catch (System.Data.SqlClient.SqlException Ex)
77 {
78 //发生问题则回滚
79 ChaosSqlTran.Rollback();
80 throw new Exception(Ex.Message);
81 }
82 }
83 }
84 #endregion
[转载]C#中使用ADO.NET连接SQL Server数据库,自动增长字段用作主键,处理事务时的基本方法的更多相关文章
- Sql Server数据库自增长字段标识列的插入或更新修改操作办法
写在前面的话:在日常的Sql server开发中,经常会用到Identity类型的标识列作为一个表结构的自增长编号.比如文章编号.记录编号等等.自增长的标识很大程度上方便了数据库程序的开发,但有时候这 ...
- 【转】PowerShell 连接SQL Server 数据库 - ADO.NET
转至:http://www.pstips.net/connect-sql-database.html PowerShell 通过ADO.NET连接SQL Server数据库,并执行SQL脚本.工作中整 ...
- JDBC连接SQL server与ADO.NET连接Sql Server对比
JDBC连接SQL server与ADO.NET连接Sql Server对比 1.JDBC连接SQL server 1)java方面目前有很多驱动能够驱动连接SQL servernet. 主流的有 ...
- JDBC连接sql server数据库的详细步骤和代码 转
JDBC连接sql server数据库的步骤如下: 1.加载JDBC驱动程序(只做一次): 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机), 这通过java.lang.C ...
- Excel VBA 连接各种数据库(三) VBA连接SQL Server数据库
本文主要涉及: VBA中的SQL Server环境配置 VBA连接SQL Server数据库 VBA读写SQL Server数据 如何安装SQL Client 系统环境: Windows 7 64bi ...
- NetBeans连接SQL server数据库教程
不废话,直接开始 1.下载sqljdbc.jar 可以从微软中国官方网站下载 SQLJDBC微软中国 笔者提供一个网盘链接Sqljdbc.jar 4个压缩包视版本选择,SQL 2012 用sqljdb ...
- JDBC连接sql server数据库及其它
JDBC连接sql server数据库的步骤如下: 1.加载JDBC驱动程序: 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机), 这通过java.lang.Class类的 ...
- JDBC连接sql server数据库的详细步骤和代码
JDBC连接sql server数据库的详细步骤和代码 JDBC连接sql server数据库的步骤如下: 1.加载JDBC驱动程序: 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Ja ...
- python连接sql server数据库实现增删改查
简述 python连接微软的sql server数据库用的第三方模块叫做pymssql(document:http://www.pymssql.org/en/stable/index.html).在官 ...
随机推荐
- 【心得】asp.net 异常:正在中止线程 引发的问题
asp.net做的一个同步程序,同步的方法是通过JQuery的Ajax调用,同步过程所需要的时间大概有几个小时吧. 当在本机运行的时候,无论是debug模式还是release模式,都能正常运行. 发布 ...
- Elasticsearch支持的字段类型
es支持下列简单的字段类型: String: string Whole number: byte, short, integer, long Floating point: float, double ...
- HttpClient向后端的WebAPI工程发送HTTP的Post请求时,返回超过了最大请求长度的异常的解决方法
文章中的内容以及解决思路参考(转载)的 http://www.jb51.net/article/88698.htm 在WPF项目中通过HttpClient向后端的WebAPI工程发送HTTP的Post ...
- [备忘]java 静态块、非静态块、静态函数、构造函数 执行顺序
原文链接:http://liqita.iteye.com/blog/1472717 java中经常有一些静态块,这是用来在生成类之前进行的初始化,无论java还C++语言中的static,都是最先初始 ...
- ajax的jquery写法和原生写法
一.ajax的简介 Ajax被认为是(Asynchronous(异步) JavaScript And Xml的缩写).现在,允许浏览器与服务器通信而无须刷新当前页面的技术都被叫做Ajax. 同步是指: ...
- mysql用户常见操作
一, 创建用户: 命令:CREATE USER 'username'@'host' IDENTIFIED BY 'password'; 说明:username - 你将创建的用户名, host - 指 ...
- Google常用拓展插件
1.web前端助手(FEhelper)提供一些实用的前端小工具,功能十分贴心 2.bookMarks Manager 一个书签管理工具 3.Clear Cache 清除浏览器的缓存,有很多供选择的条目 ...
- uvm_analysis_port——TLM1事务级建模方法(二)
UVM中的TLM1端口,第一类是用于uvm_driver 和uvm_sequencer连接端口,第二类是用于其他component之间连接的端口,如uvm_monitor和uvm_scoreboard ...
- 优化Linux的内核参数来提高服务器并发处理能力
提高Linux系统下的负载能力,可以使用nginx等原生并发处理能力就很强的web服务器 使用Apache的可以启用其Worker模式,来提高其并发处理能力 修改Linux的内核相关TCP参数,来最大 ...
- Flexbox与Grid属性比较
网格容器(container)属性 网格项目(item)属性 Flex容器(container)属性 Flex项目(item)属性