Dapper基础入门
2018-02-07 14:22 糯米粥 阅读(2443) 评论(0) 编辑 收藏 举报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