1.1.Dapper呼叫存盤程序
存盤程序是一組預編譯的SQL陳述句,
使用存盤程序有以下優點:
1.允許模塊化程式設計,就是說只需要創建一次,在以后的程式中就可以呼叫該程序任意次,
2.允許更快地執行,如果某操作需要大量SQL陳述句或重復執行對應的SQL陳述句,存盤程序比SQL陳述句執行的更快,
3.減少網路流量,例如一個需要數百行的SQL代碼的操作有一條執行陳述句完成,不需要在網路中發送數百行代碼,
4.更好的安全機制,對于沒有權限執行存盤程序的用戶,也可以授權它們執行存盤程序,
1.1.1.使用Dapper呼叫無引數的存盤程序
這里我首先在資料庫中創建了一個基于DapperDemo資料庫的無引數的存盤程序:dbo.P_stuMarkInfo,具體的存盤程序陳述句已上傳至github:https://github.com/devyf/Dapper-.git

這里我基于wiform界面按鈕操作來呼叫我的后臺存盤程序,
點擊“未通過考試學生名單”按鈕,會呼叫后臺在資料庫對應創建的”dbo. P_stuMarkInfo”存盤程序:

對應后臺的無參存盤程序點擊呼叫執行代碼:
/// <summary> /// 點擊按鈕,查詢未能通過考試的學生名單,呼叫無引數的存盤程序,默認及格線為60分 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { List<StuInfo> stuList = new List<StuInfo>(); using (IDbConnection db = new SqlConnection(DBHelper.ConnString)) { stuList = db.Query<StuInfo>("dbo.P_stuMarkInfo", //存盤程序的名稱 null, //存盤程序的引數 null, //事務物件 true, //是否快取 null, //獲取或設定在終止執行命令的嘗試并生成錯誤之間的等待時間 CommandType.StoredProcedure //指定的sql陳述句為存盤程序型別 ).ToList(); } if (stuList.Count > 0) { stuList.ForEach(stu => this.textBox1.Text += stu.StuName + " "); } }
執行效果如下:

1.1.2.使用Dapper呼叫有引數(有回傳值)的存盤程序
這里我繼續添加sql來創建了一個有引數、有回傳值的存盤程序,如下:
----存盤程序的創建:②帶引數的存盤程序 ----筆試和機試的及格線由用戶指定,并且統計出未通過考試的人數 if exists (select * from sysobjects where name='P_stuMarkInfo1') drop proc P_stuMarkInfo1 go create proc P_stuMarkInfo1 @writeLevel int, ----輸入引數:筆試及格線 @labLevel int, ----輸入引數:機試及格線 @examNum int output ----輸出引數:未通過考試的人數 as select @examNum = count(*) from stuinfo where stuNo not in (select stuNo from stumark where writtenExam >= @writeLevel and labExam>=@labLevel) ----執行存盤程序 declare @countNum int exec P_stuMarkInfo1 60, 60, @countNum output print '未通過考試的人數:' + convert(varchar(20), (@countNum))
存盤程序陳述句均已上傳至github:https://github.com/devyf/Dapper-.git
具體存盤程序創建時需要對應在當前資料庫下執行并保存,如下圖:

這里對應前臺winform界面上輸入和輸出引數設定如下,點擊”未通過考試學生人數”按鈕可以呼叫后臺的存盤程序:

后臺呼叫有引數的存盤程序代碼如下:
/// <summary> /// 點擊按鈕,通過設定的筆試成績和機試成績去動態呼叫帶引數的存盤程序 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button2_Click(object sender, EventArgs e) { //準備存盤程序的三個引數:兩個是輸入引數,一個是輸出引數 var param = new DynamicParameters(); //動態引數類 try { param.Add("@writeLevel", int.Parse(this.writeLev.Text)); //存盤程序的輸入引數賦值 param.Add("@labLevel", int.Parse(this.labLev.Text)); param.Add("@examNum", 0, DbType.Int32, ParameterDirection.Output); //標注為輸出引數 } catch (Exception ex) { MessageBox.Show(ex.Message); } using (IDbConnection db = new SqlConnection(DBHelper.ConnString)) { db.Execute("dbo.P_stuMarkInfo1", //指定存盤程序名稱 param, //存盤程序引數 null, //存盤程序事務 null, //執行等待時間 CommandType.StoredProcedure //指定執行為存盤程序型別 ); //通過引數呼叫Get方法來獲取回傳值 int outNum = param.Get<int>("@examNum"); //放置到文本框中 this.nopassNum.Text = outNum.ToString(); MessageBox.Show("存盤程序執行成功!"); } }
1.2.Dapper執行事務操作
事務的概念:在關系型資料庫中,一個事務可以是一條SQL陳述句,一組SQL陳述句或者整個程式,
事務特性:
事務是恢復和并發控制的基本單位,
事務應該具有4個屬性:原子性、一致性、隔離性、持久性,這四個屬性通常稱為ACID特性,
原子性(atomicity):一個事務是一個不可分割的作業單位,事務中包括的所有操作要么都做,要么都不做,
一致性(consistency):事務必須是使資料庫從一個一致性狀態變到另一個一致性狀態,一致性與原子性是密切相關的,
隔離性(isolation):一個事務的執行不能被其它事務干擾,即一個事務內部的操作及使用的資料對并發的其它事務是隔離的,并發執行的各個事務之間不能互相干擾,
持久性(durability):持久性也稱為永久性(permanence),指一個事務一旦提交,它對資料庫中資料的改變就應該是永久性的,接下來的其它操作或故障不應該對其有任何影響,
使用Dapper操作資料庫事務,這里基于winform界面執行資料庫中兩張表(主表stuinfo、從表stumark)進行洗掉操作,使用Dapper操作事務進行提交、洗掉、回滾操作,具體后臺代碼如下:
/// <summary> /// 洗掉按鈕點擊執行事務操作 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void delBtn_Click(object sender, EventArgs e) { //執行界面操作,根據主表學生表的ID去洗掉相關聯的資訊 //事務操作:根據輸入的學生ID編號,洗掉從表,洗掉主表中的資料資訊列 int delId = int.Parse(this.txtDelID.Text); //取出要洗掉的學生表的學號 using (IDbConnection db = new SqlConnection(DBHelper.ConnString)) { db.Open(); //基于事務操作的特殊性:執行事務之前需要優先開啟連接 //try catch陳述句使用外側代碼:快捷鍵:ctrl+k、ctrl+s //創建事務物件 IDbTransaction transaction = db.BeginTransaction(); //開啟資料庫的事務 try { //根據用戶輸入的學號ID進行洗掉的操作:先洗掉從表,再洗掉主表的資訊 string delSql1 = "delete from stuinfo where stuNo = @stuNo"; //主表 string delSql2 = "delete from stumark where stuNo = @stuNo"; //從表 //執行洗掉操作 db.Execute(delSql2, new { stuNo = delId }, transaction, null, null); db.Execute(delSql1, new { stuNo = delId }, transaction, null, null); //提交事務 transaction.Commit(); MessageBox.Show("洗掉成功!"); } catch (Exception ex) { //出現例外,需要回滾事務 transaction.Rollback(); MessageBox.Show("出現例外:" + ex.Message); } finally { db.Close(); } } }
執行洗掉從表、主表操作,成功從前臺界面上洗掉ID為”1006”的資料:

對應資料庫中也隨即洗掉:


對應如果交換delSql1與delSql2的執行順序,這時因為先洗掉主表,而在從表上有資料外鍵的關聯,會執行資料回滾rollback操作,無法進行資料的洗掉操作:

可以看到catch例外之后,資料庫中資料”1005”并未執行資料列的洗掉操作:

1.3.Dapper進行多表查詢
Dapper框架可以基于資料庫sql陳述句進行資料庫欄位映射,并使用splitOn進行型別與回傳值之間的劃分,
下面基于兩個實體來簡單介紹一下Dapper進行多表查詢回傳值劃分案例:
實體一:
①首先基于之前的dbo.stuinfo表與dbo.stumark表進行多表連接查詢,對應sql陳述句與查詢結果如下:

②基于這個連接查詢的結果,使用Dapper框架進行Query查詢封裝查詢映射,具體代碼如下:
private void button1_Click(object sender, EventArgs e) { using (IDbConnection db = new SqlConnection(DBHelper.ConnString)) { var sql = "select * from stuinfo inner join stumark on stuinfo.stuNo = stumark.stuNo"; //執行查詢:多表(型別一,型別二,回傳值) var list = db.Query<StuInfo, StuMark, StuInfo>( sql, (students, score) => { return students; }, //變數students對應的StuInfo型別,scores對應StuMark型別 null, //存盤程序的引數 null, //事務 true, //快取 splitOn: "stuNo" //該引數是用來劃分查詢中的欄位是屬于哪個表的 splitOn可以省略 ); /*splitOn:stuNo 劃分查詢中的欄位是屬于哪個表的,也就是查詢結構映射到哪個物體,上邊的sql運行時,會從查詢結果所有 欄位串列的最后一個欄位進行匹配,一直找到stuNo這個欄位(大小寫不計),找到的第一個stuNo欄位匹配就是Query引數中 StuInfo類的stuNo屬性,那么從stuNo到最后一個欄位都屬于StuInfo,StuNo以前的欄位都被映射到StuMark這張表 通過(T,P)=>(return T)把兩個類的實體決議出來*/ this.dgvContent.DataSource = list; } }
執行界面點擊操作,加載資料庫查詢映射結果如下圖所示:

實體二:
繼續使用查詢陳述句進行資料分割操作,這里同樣創建了兩個資料點擊顯示按鈕界面進行查詢操作:

查看資料后臺代碼:
private void button1_Click(object sender, EventArgs e) { using (IDbConnection db = new SqlConnection(DBHelper.ConnString)) { List<Customer> userList = new List<Customer>(); string sql = @"select u.*, r.* from UserInfo u inner join UserRole ur on ur.UserId = u.UserId inner join Role r on r.RoleId = ur.RoleId"; userList = db.Query<Customer, Role, Customer>( //第三個引數是回傳值型別 sql, (user, role) => { user.Role = role; return user; }, null, null, true, "RoleId", //分割資料列字串 null, null ).ToList(); this.dataGridView1.DataSource = userList; //列印其中單個字符 if (userList.Count > 0) { userList.ForEach(item => Console.WriteLine("userName:" + item.Username + "passWord:" + item.PasswordHash + "Role:" + item.Role)); } } } private void button2_Click(object sender, EventArgs e) { using (IDbConnection db = new SqlConnection(DBHelper.ConnString)) { List<User> userList = new List<User>(); string sql = @"select u.UserId, u.UserName, u.PasswordHash, r.RoleId, r.RoleName from UserInfo u inner join UserRole ur on ur.UserId = u.UserId inner join Role r on r.RoleId = ur.RoleId"; Dictionary<int, User> dic = new Dictionary<int, User>(); userList = db.Query<User, Role, User>( sql, (user, role) => { User tempUser; if (!dic.TryGetValue(user.UserId, out tempUser)) { tempUser = user; dic.Add(user.UserId, tempUser); } tempUser.Role.Add(role); return user; }, null, null, true, "RoleId", null, null ).ToList(); this.dataGridView2.DataSource = userList; //列印其中單個字符 if (userList.Count > 0) { userList.ForEach(item => Console.WriteLine("userName:" + item.Username + "passWord:" + item.PasswordHash + "Role:" + item.Role.First().RoleName)); } } }
查詢結果如下圖所示:

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/33.html
標籤:C#
