目錄
寫在前面
在上一小節中,我們學習、實踐和總結記錄了Dapper的基礎用法。而這一小節,我們繼續深入的學習一下Dapper這個小型
ORM框架的其他用法。在這個實列中,我們會用到兩個有關聯的表。
前期准備
首先,還是沿用之前的的項目。庫還是原來的DemoDb數據庫。如還是不清楚的,可以看上一篇。
在DemoDb數據庫新增產品表
//用戶表
create table[sys_user](
[user_id] [nvarchar](36) primary key not null,
[u_id] [nvarchar](20) null,
[u_password] [nchar](50) null,
[gender] [nchar](1) null,
[user_name] [nvarchar](50) null,
[creation_time] [datetime] default(getdate()) null,
[status] [nvarchar](1) null,
)
//產品表
create table [sys_product](
[productid] [nvarchar](36) primary key not null,
[productname] [nvarchar](50) null,
[productDesc] [nvarchar](50) null,
[CreateTime] [datetime] defatul(getdate()) null,
[user_id] [nvarchar](36) null,
)
在Model 中添加 產品表的類
//用戶
public class sys_user_sqlserver
{
[DisplayName("用戶主鍵")]
public string user_id { get; set; }
[DisplayName("登錄名稱")]
public string u_id { get; set; }
[DisplayName("登錄密碼")]
public string u_password { get; set; }
[DisplayName("性別")]
public string gender { get; set; }
[DisplayName("姓名")]
public string user_name { get; set; }
[DisplayName("創建時間")]
public string creation_time { get; set; }
[DisplayName("狀態")]
public string status { get; set; }
}
//產品
public class sys_product_sqlserver
{
[DisplayName("產品主鍵")]
public string productid { get; set; }
[DisplayName("產品名稱")]
public string productname { get; set; }
[DisplayName("產品描述")]
public string productDesc { get; set; }
[DisplayName("用戶主鍵")]
public string user_id { get; set; }
//public sys_user_sqlserver userown { get; set; }
[DisplayName("創建時間")]
public DateTime CreateTime { get; set; }
}
Dapper 單表批量添加
using System.Configuration;//ConfigurationManager
using Dapper;//SqlMapper
using System.Data;//IDbConnection
using System.Data.SqlClient; //SqlConnection
using Newtonsoft.Json;//
using MySql.Data.MySqlClient;
using Newtonsoft.Json.Linq;
using System.Diagnostics;//mysql
/*連接字符串*/
private static string connstr_sqlserver = ConfigurationManager.ConnectionStrings["lc"].ToString();
/// <summary>
/// 單表批量添加
/// </summary>
/// <param name="user">泛型集合</param>
/// <returns>成功返回1,失敗返回0</returns>
[HttpPost]
public int Add_Many(List<sys_user_sqlserver> user)
{
/*模擬數據*/
user = new List<sys_user_sqlserver> {
new sys_user_sqlserver { user_id =Guid.NewGuid().ToString(), u_id = "Admin", u_password = "admin001", gender = "m", user_name = "管理員", status = "y" },
new sys_user_sqlserver { user_id =Guid.NewGuid().ToString(), u_id = "User", u_password = "user001", gender = "m", user_name = "用戶", status = "y" },
new sys_user_sqlserver { user_id =Guid.NewGuid().ToString(), u_id = "ZhangSan", u_password = "zhangsan001", gender = "m", user_name = "張三", status = "y" },
new sys_user_sqlserver { user_id =Guid.NewGuid().ToString(), u_id = "LiSi", u_password = "LiSi001", gender = "w", user_name = "李思", status = "y" },
new sys_user_sqlserver { user_id =Guid.NewGuid().ToString(), u_id = "ZhaoQian", u_password = "zhaoqiao001", gender = "w", user_name = "趙錢", status = "y" },
};
/*聲明結果*/
int result = 0;
/*連接Sqlserver 數據庫*/
using (IDbConnection conn = new SqlConnection(connstr_sqlserver))
{
/*sql 語句*/
string sql_add = @"insert into sys_user(user_id,u_id,u_password,gender,user_name,status)";
sql_add += " values (newid(),@u_id,@u_password,@gender,@user_name,@status)";
/*執行Execute(參數1,參數2) 參數1:sql語句,參數2:(可以是一個對象也可以是一個泛型集合)*/
int results = conn.Execute(sql_add, user);
if (results > 0) { result = 1; }
}
/*成功返回1,失敗返回0*/
return result;
}
在Dapper 多表查詢
/// <summary>
/// 多表查詢
/// </summary>
/// <returns></returns>
[HttpGet]
public JsonResult ManyToOne()
{
using (IDbConnection conn = new SqlConnection(connstr_sqlserver))
{
string sql = "select p.productid,p.productname,p.productDesc,u.user_name from sys_product p ";
sql += "join sys_user u on p.user_id=u.user_id";
#region 方式1 返回泛型
var product = conn.Query<sys_product_sqlserver, sys_user_sqlserver, sys_product_sqlserver>(sql,
(products, users) =>
{
products.userown = users; return products;
}, splitOn: "user_name");
#endregion
#region 方式2 默認返回 dynamic
////var product = conn.Query(sql);
#endregion
return Json(product, JsonRequestBehavior.AllowGet);
}
}
在Dapper 調用存儲過程
/*創建存儲過程*/
create proc proc_queryUser
@user_id varchar(50)
as
begin
select * from sys_user where user_id=@user_id;
end
/*在程序中使用Dapper調用存儲過程*/
/// <summary>
/// Dapper 調用存儲過程
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public JsonResult Get_Proc(string id)
{
/*模型接收數據*/
stirng Id="7384A533-44FA-4358-8171-0162F4950292";
/*打開數據庫連接*/
using (IDbConnection conn = new SqlConnection(connstr_sqlserver))
{
#region 方法1
//var result = conn.Query<sys_user_sqlserver>("proc_queryUser",
//new { user_id = id }, null, true, null,
//CommandType.StoredProcedure);
#endregion
#region 方法2
/*調用存儲過程*/
var result = conn.Query<sys_user_sqlserver>("proc_queryUser",
new { user_id = id },
commandType: CommandType.StoredProcedure);
#endregion
/*返回結果集*/
return Json(result, JsonRequestBehavior.AllowGet);
}
}
在Dapper 使用QueryMultiple進行多表查詢
錯誤寫法:
public SqlMapper.GridReader Get_Readers_Data()
{
using (IDbConnection conn = new SqlConnection(connstr_sqlserver))
{
string sql = @"select * from sys_user;select * from sys_product;";
#region 方式1 QueryMultiple(sql語句);
var data = conn.QueryMultiple(sql);
#endregion
#region 方式2 QueryMultiple(連接字符串,sql語句);
//var data = SqlMapper.QueryMultiple(conn, sql);
#endregion
return data;
}
}
public JsonResult Get_All_Data()
{
var all = Get_Reader_Data();
var users = all.Read<sys_user_sqlserver>().ToList();
var products = all.Read<sys_product_sqlserver>().ToList();
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("user",users);
dic.Add("product",products);
return Json(dic, JsonRequestBehavior.AllowGet);
}
這時我們運行程序,會發現出現如圖的錯誤。錯誤:閱讀器關閉時嘗試調用 FieldCount無效[解決方案]。
分析錯誤原因:
*.首先:使用using{}作用域之后,連接會自動關閉。
*.其次:使用的是DataSet 讀取數據庫是它會把讀到的數據數據存放在本地內存中。但是,Reader則不會。
*.最后:它只是指向了數據,連接關閉后用reader讀取數據當然無法實現。
所以,正確的做法是,去除Using{}作用域。
//正確做法
public SqlMapper.GridReader Get_Readers_Data()
{
/*打開數據庫連接*/
IDbConnection conn = new SqlConnection(connstr_sqlserver);
/*sql語句*/
string sql = @"select * from sys_product; select * from sys_user";
#region 方式1 QueryMultiple(sql語句);
/*調用 QueryMultiple 返回過個結果集 */
var data = conn.QueryMultiple(sql);
#endregion
#region 方式2 QueryMultiple(連接字符串,sql語句);
//var data = SqlMapper.QueryMultiple(conn, sql);
#endregion
return data;
}
public JsonResult Get_All_Data()
{
var all = Get_Reader_Data();
var users = all.Read<sys_user_sqlserver>().ToList();
var products = all.Read<sys_product_sqlserver>().ToList();
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("user",users);
dic.Add("product",products);
return Json(dic, JsonRequestBehavior.AllowGet);
}
注意: 這里查詢表順序和讀取表的順序必須要一樣。如果兩者順序不一樣是沒有數據返回的。 會出現返回值都是NULL的情況。而造成這樣的原因是Reader 是按照查詢的結果依次讀取顯示的。 所以,查詢表順序和讀取表的順序必須一樣。否則就會出現類似於下圖的情況。
如圖所示:在Dapper 使用事務進行多表添加
[HttpPost]
public int Get_Tran_Add(List<sys_product_sqlserver> product, sys_user_sqlserver user)
{
int result;
/*連接sqlserver 數據庫*/
using (IDbConnection conn = new SqlConnection(connstr_sqlserver))
{
/*模擬數據*/
var ID = Guid.NewGuid();
user = new sys_user_sqlserver { user_id = ID.ToString(), u_id = "admin", u_password = "admin", gender = "m", user_name = "管理員", status = "y" };
product = new List<sys_product_sqlserver> {
new sys_product_sqlserver{productid=Guid.NewGuid().ToString(),productname="產品1",productDesc="產品描述1",user_id=ID.ToString()},
new sys_product_sqlserver{productid=Guid.NewGuid().ToString(),productname="產品2",productDesc="產品描述2",user_id=ID.ToString()},
new sys_product_sqlserver{productid=Guid.NewGuid().ToString(),productname="產品3",productDesc="產品描述3",user_id=ID.ToString()},
new sys_product_sqlserver{productid=Guid.NewGuid().ToString(),productname="產品4",productDesc="產品描述4",user_id=ID.ToString()},
new sys_product_sqlserver{productid=Guid.NewGuid().ToString(),productname="產品5",productDesc="產品描述5",user_id=ID.ToString()}
};
/*sql語句*/
string sql1 = @"insert into sys_user(user_id,u_id,u_password,gender,user_name,status)";
sql1 += " values (@user_id,@u_id,@u_password,@gender,@user_name,@status)";
string sql2 = @"insert into sys_product(productname,productDesc,user_id)";
sql2 += " values (@productname,@productDesc,@user_id)";
/*注意:要記得打開連接。否則會報錯:無效操作。連接被關閉。*/
conn.Open();
/*開始事務*/
IDbTransaction tran = conn.BeginTransaction();
try
{
/*執行事務*/
var resultOne = conn.Execute(sql1, user, tran);
var resultTwo = conn.Execute(sql2, product, tran);
/*提交事務*/
tran.Commit();
result = 1;
}
catch (Exception)
{
/*回滾事務*/
tran.Rollback();
result = 0;
throw;
}
}
/*成功返回1,失敗返回0*/
return result;
}
注意: 在使用事務的時候注意要加上dbConnection.Open(),因為在BeginTransaction時要求連接是打開的。 而在不使用事務的時候,簡單的增刪改查可以不用這一句,因為Execute方法中有Open。 否則會報錯:無效操作。連接被關閉。
在Dapper 使用事務進行多表編輯
[HttpPost]
public int Get_Tran_Edit(List<sys_product_sqlserver> product, sys_user_sqlserver user)
{
int result;
/*連接sqlserver 數據庫*/
using (IDbConnection conn = new SqlConnection(connstr_sqlserver))
{
//注意要加上dbConnection.Open(),因為在BeginTransaction時要求連接是打開的。而
//在不使用事務的時候,簡單的增刪改查可以不用這一句,因為Execute方法中有Open。否則會報錯:無效操作。連接被關閉。
/*模擬接收數據*/
var ID = "EF2D72DD-5D45-482A-A26E-FF3AF3A39DE9";
user = new sys_user_sqlserver { user_id = ID, u_id = "admin1", u_password = "admin1", gender = "w", user_name = "管理員1", status = "n" };
product = new List<sys_product_sqlserver> {
new sys_product_sqlserver{productid="04245342-1855-4171-B408-2A04FCF5696B",productname="產品11",productDesc="產品描述11",user_id=ID},
new sys_product_sqlserver{productid="C268A332-38B5-49E9-AFC1-E6E9EB62D2A2",productname="產品21",productDesc="產品描述21",user_id=ID},
new sys_product_sqlserver{productid="823E4F43-31FC-4355-BA12-925AC7704340",productname="產品31",productDesc="產品描述31",user_id=ID},
new sys_product_sqlserver{productid="93E8829E-5ED1-45BF-B979-E22405D092D1",productname="產品41",productDesc="產品描述41",user_id=ID},
new sys_product_sqlserver{productid="6EF52CA5-AB9B-41E1-B335-16C86F2A445C",productname="產品51",productDesc="產品描述51",user_id=ID}
};
/*sql語句*/
string sql_add = @"update sys_user set u_id=@u_id,u_password=@u_password,gender=@gender,";
sql_add += "user_name=@user_name,status=@status where user_id=@user_id";
string sql = @"update sys_product set productname=@productname,productDesc=@productDesc,user_id=@user_id";
sql += " where productid=@productid";
/*注意:要記得打開連接。否則會報錯:無效操作。連接被關閉。*/
conn.Open();
/*開始事務*/
IDbTransaction tran = conn.BeginTransaction();
try
{
/*執行事務*/
var resultOne = conn.Execute(sql_add, user, tran);
var resultTwo = conn.Execute(sql, product, tran);
/*提交事務*/
tran.Commit();
result = 1;
}
catch (Exception)
{
/*事務回滾*/
tran.Rollback();
result = 0;
throw;
}
}
/*6.成功返回結果1,失敗返回結果0*/
return result;
}
在Dapper 使用事務進行多表刪除
[HttpPost]
public int Get_Tran_Del()
{
int result;
/*連接sqlserver 數據庫*/
using (IDbConnection conn = new SqlConnection(connstr_sqlserver))
{
//注意要加上dbConnection.Open(),因為在BeginTransaction時要求連接是打開的。而
//在不使用事務的時候,簡單的增刪改查可以不用這一句,因為Execute方法中有Open。否則會報錯:無效操作。連接被關閉。
/*注意:要記得打開連接。否則會報錯:無效操作。連接被關閉。*/
conn.Open();
/*開始事務*/
IDbTransaction transaction = conn.BeginTransaction();
try
{
/*執行事務*/
string query1 = "delete from sys_user where user_id = @user_id";
string query2 = "delete from sys_product where user_id = @user_id";
conn.Execute(query1, new { user_id = "f2ffed38-9f43-4088-80af-138990a76e60" }, transaction, null, null);
conn.Execute(query2, new { user_id = "f2ffed38-9f43-4088-80af-138990a76e60" }, transaction, null, null);
/*提交事務*/
transaction.Commit();
result = 1;
}
catch (Exception ex)
{
/*回滾事務*/
//出現異常,事務Rollback
transaction.Rollback();
result = 0;
throw new Exception(ex.Message);
}
}
return result;
}
總結
好記性不如‘爛筆頭’。到目前為止,總結了Dapper 常用的一些操作。如果項目小,又對性能有較高要求的話,可以選擇Dapper 這個小型的ORM框架進行項目的快速開發。