Dapper基礎入門


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM