Dapper是一個輕量級的ORM。之前最常用的ORM是EF,其實EF底層是Ado.net實現的。
現在基本上已經遠離SqlHelper時代了。
Dapper是開源的 https://github.com/StackExchange/Dapper
那從基本的增刪改查開始
配置好文件
在Nuget可以直接導入
引入:using Dapper;
當前使用的版本

獲取連接字符串
var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["connString"].ConnectionString);
Dapper支持多數據庫的本質是因為Dapper是對IDBConnection接口進行了方法擴展,比如你看到的SqlMapper.cs,一旦你這樣做了,我們也知道,
SqlConnection,MysqlConnection,OracleConnection都是繼承於DBConnection,而DBConnection又是實現了IDBConnection的接口
Insert
var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["connString"].ConnectionString); Model.Show insert = new Model.Show { name = "insert", remark = "新增" }; //insert conn.Execute("insert into show (Name,remark)values(@name,@remark)", insert); conn.Execute("insert into show (Name,remark)values(@name,@remark)", new { @name = insert.name, //是否加前綴 @ 都可以 remark = insert.remark }); List<Model.Show> ls = new List<Model.Show> { new Model.Show{name="1",remark="2"}, new Model.Show{name="11",remark="21"}, new Model.Show{name="12",remark="22"} }; //批量插入 conn.Execute("insert into show (Name,remark)values(@name,@remark)", ls); //匿名類也行 var anonymous = new List<dynamic> { new {name="51",remark="2"}, new {name="61",remark="2"}, new {name="71",remark="2"}, new {name="81",remark="2"}, }; //批量插入 int r1 = conn.Execute("insert into show (Name,remark)values(@name,@remark)", anonymous);
delete
int id = 250; conn.Execute("delete show where id = @id", new { id }); //變量名id必須跟@id匹配。才能映射 conn.Execute("delete show where id = @id", new { @id = 251 }); //也可以
//刪除也可以傳對象
Model.Show insert = new Model.Show { id = 256, name = "71", remark = "新增" };
conn.Execute("delete show where id = @id and name=@name", insert); //也可以
update
conn.Execute("update show set name='update' where id =@id", new { id = 252 }); Model.Show insert = new Model.Show { id = 258, name = "insert", remark = "新增" }; //傳對象 conn.Execute("update show set name='update' where id =@id", insert);
Query
查詢也有多種方式,首先看簡單的查詢
//query 無參數查詢 var list1 = conn.Query("select * from show");
當然。一般實際應用中。都是返回便於操作的實體類,SqlHelper時代是。獲取Table轉Model,而dapper自動可以Mapper到Object
conn.Query<Model.Show>("select * from show where id in @ids", new { @ids = new[] { 1, 2, 3 } })
這樣寫法也行
int[] ids = { 1, 2, 3 }; var list3 = conn.Query<Model.Show>("select * from show where id in @ids", new { ids });
或者:
conn.Query<Model.Show>("select * from show where id in (@ids)", new { ids=252 });
可以看到。這樣寫的方式 in 后面的有括號和沒有括號的區別
dapper 多表查詢,dapper可以實現多個sql一起查詢,然后返回多個結果。需要用QueryMultiple 方法
比如:三個條件的sql
string multsql = @"select * from show where id=@id
select * from show where name=@name
select * from show where remark=@remark";
當然。我這里都是from show ,你可以from A from B from C 都是可以的
//多表查詢 這里不單單是一個表的查詢,可以是多個表 from A from B... string multsql = @"select * from show where id=@id select * from show where name=@name select * from show where remark=@remark"; SqlMapper.GridReader gridReader = conn.QueryMultiple(multsql, new { id = 1, name = "張三", remark = "海南" }); if (!gridReader.IsConsumed) //沒有釋放 true代表釋放 { var g1 = gridReader.Read<Model.Show>(); //轉實體類 var g2 = gridReader.Read<Model.Show>(); var g3 = gridReader.Read<Model.Show>(); //var g4 = gridReader.Read(); //基本讀取方式,只返回3個表。不能讀第4次 }
可以看到。QueryMultiple 有兩種讀取方式 ,很方便
var g3 = gridReader.Read<Model.Show>(); //轉實體類
var g4 = gridReader.Read(); //基本讀取方式
這里需要注意 的是,參數部分順序:new { id = 1, name = "張三", remark = "海南" }
需要跟sql 中參數的順序是一一對應的。 id=@id name=@name remark=@remark
Read讀取的順序也需要返回的順序一樣,返回幾個表。就只能Read幾次
query join 操作
dapper 提供了join操作,
比如我現在有兩個表join
select * from Show s right join info i on s.Name = i.Name
實體類
代碼:
var ss1 = conn.Query<Model.Show, Model.info, Model.Show>("select * from Show s right join info i on s.Name = i.Name", (show, info) => { show.info = info; return show; });
看看Query參數,一個泛型委托 Func
執行看看效果,跟上面sql一樣的結果
這里用到了select * 這樣查詢效率是不可取的,
在實際中。我們一般會select 出需要的字段,或者指定字段。或者過濾不需要的字段
比如:select s.Name,s.remark,s.id,i.name,i.address,i.id from Show s right join info i on s.Name = i.Name
var ss = conn.Query<Model.Show, Model.info, Model.Show>("select s.Name,s.remark,s.id,i.name,i.address,i.id from Show s right join info i on s.Name = i.Name", (show, info) => { show.info = info; //賦值 return show; });
執行結果后。你會發現 info 中除了id有值,其余屬性是沒有獲取到值的
看下Query方法有個默認值, splitOn = "Id"

我的sql中select s.Name,s.remark,s.id,i.name,i.address,i.id
Dapper找到了最后一個id。來分割讀取數據。分割后。左邊是前面的表(show)右邊是后面的表(info),
也就是方法中的 TFirst 和TSecond

然后分別映射
這就是為什么show有值,而info只有id有值的原因
為了進一步測試我說的正確性。我修改sql :select s.Name,s.remark,s.id,i.name,i.address
如果按照上面說的。s.id應該是show表的id。那么分割后,映射到了info表,執行看看結果,是正確的
要解決這個問題。就只能手動指定splitOn的值。這里應該是splitOn:name
修改代碼:
執行結果正確了。info的id沒值。是因為select 過濾掉了
當然。這樣僅僅 是兩個表join。如果是三個表,或者更多。在項目中還是有的吧,2個以上的表join。這樣就不可取了
可以把多個類整合到一個類下面。show和info都有同名 的name。所以需要取別名
修改sql
select s.Name,s.remark,s.id ,i.name as infoName,i.address as infoAddress,i.id as infoId from Show s right join info i on s.Name = i.Name
var ss3 = conn.Query<Model.result>("select s.Name,s.remark,s.id ,i.name as infoName,i.address as infoAddress,i.id as infoId from Show s right join info i on s.Name = i.Name");
執行結果:
注意一點:
上面說了 splitOn 默認是id 分割。如果sql中沒有指定id。則需要手動指定。否則會報錯
比如:我sql中沒有默認的id
dapper事物
模擬一個刪除數據失敗,事物回滾的操作
假設刪除 id=259的數據
//創建一個事物 using (var trans = conn.BeginTransaction()) //開啟數據庫事物 { try { conn.Execute("delete show where id = @id", new { id = 259 }, trans); int a = 0; int b = 5 / a; //此處會異常,導致事物回滾 trans.Commit(); //提交事物 } catch (Exception ex) { //事物回滾 trans.Rollback(); } }
運行發現報錯:無效操作。連接被關閉。
因為dapper在CRUD操作中會自動判斷連接是否打開:ConnectionState.Closed
而事物不會,則需要手動打開連接
conn.Open(); //先打開連接
事物已經提交。但沒有Commit前不會生效,在cath中回滾事物 trans.Rollback();
存儲過程
我這里存儲過程,就不在編寫了,用之前的列子 http://www.cnblogs.com/nsky/p/7766653.html
用CommandType.StoredProcedure 標記是存儲過程
如果只執行存儲過程。不需要獲取返回值和輸出參數。直接這樣既可
//不獲取輸出參數
var qq = conn.Query<Model.Show>("[proc_show01]", new { id = 1, ck = 1 }, commandType: CommandType.StoredProcedure);
執行結果:

如果考慮安全,可以用參數化
DynamicParameters dp = new DynamicParameters(); dp.AddDynamicParams(new { @id = 1 }); dp.AddDynamicParams(new { @ck = 1 }); //不獲取輸出參數 var qq = conn.Query<Model.Show>("[proc_show01]", dp, commandType: CommandType.StoredProcedure);
DynamicParameters 還有一個參數的構造函數
可以這樣寫:
DynamicParameters dp = new DynamicParameters(new { id = 1,ck=1 });
需要獲取輸出參數和返回值
//獲取輸出參數 DynamicParameters dp = new DynamicParameters(); dp.Add("@id", 0, DbType.Int32, ParameterDirection.Output); //輸出參數。 dp.Add("@ck", 0, DbType.Int32, ParameterDirection.Output); //輸出參數 dp.Add("@returnValue", 0, DbType.Int32, ParameterDirection.ReturnValue); //返回值 var qq1 = conn.Query<Model.Show>("[proc_show01]", dp, commandType: CommandType.StoredProcedure); var ck = dp.Get<int>("@ck"); //輸出參數 var id2 = dp.Get<int>("@id"); //輸出參數,是新增后的id值 var returnValue = dp.Get<int>("@returnValue");
執行結果:
也許你看不明白,這些值的說明。那看看我存儲過程的邏輯
因為僅僅是測試。所以代碼中的命名沒有那么規范~~~~
參考:
http://www.cnblogs.com/yiting/p/5600262.html
https://yq.aliyun.com/articles/40182
https://www.cnblogs.com/huangxincheng/p/5828470.html
https://www.cnblogs.com/dunitian/p/5221058.html
