Dapper入门

Dapper入门Dapper 一 dapper 是什么 dapper 是一款轻量级的 ORM Object Relationship Mapper 它负责数据库和编程语言之间的映射 SqlConnectio MysqlConnect OracleConnec 都是继承于 DBConnection

大家好,我是讯享网,很高兴认识大家。

Dapper

一、dapper是什么

dapper是一款轻量级的ORM(Object Relationship Mapper),它负责数据库和编程语言之间的映射。SqlConnection,MysqlConnection,OracleConnection都是继承于DBConnection,而DBConnection又是实现了IDBConnection的接口。因为Dapper是对IDBConnection接口进行了方法扩展,比如你看到的SqlMapper.cs,所以dapper支持多数据库。

二、dapper的简单使用

Dapper总结(一)—基本CRUD操作 (wjhsh.net)

https://www.cnblogs.com/nsky/p/8425410.html

0、准备的测试类
 1 //用户类 2 public class UserInfo 3 { 4 public int UId { get; set; }//用户Id 5 public string UserName { get; set; }//用户名 6 public int Age { get; set; }//年龄 7 public int RoleId { get; set; }//角色Id 8 9 } 10 //角色类 11 public class RoleInfo 12 { 13 public int RId { get; set; }//角色Id 14 public string RoleName { get; set; }//角色名 15 } 

讯享网
1、execute方法,返回值为int类型,表示受影响行数
讯享网var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["connString"].ConnectionString); Model.Show insert = new Model.Show { name = "insert", remark = "新增" }; //以下注意一点:下面操作是基于多个文件来的,所以可能出现不同的字符串(例如:Show是一个表) //插入数据 2 //单条数据插入 3 int result = conn.Execute("insert into userinfo values(@username,@age,@roleid)", new 4 { 5 @UserName = "user1", //是否加前缀 @ 都可以 6 Age = 20, 7 RoleId = 1 8 }); // result=1 9 10 //多条数据插入 11 List<UserInfo> users=new List<UserInfo>(){ 12 new UserInfo(){UserName="user2",Age=22,RoleId=1}, 13 new UserInfo(){UserName="user3",Age=23,RoleId=1}, 14 new UserInfo(){UserName="user4",Age=24,RoleId=2}, 15 }; int result2 = conn.Execute("insert into userinfo values(@username,@age,@roleid)", users); // result2=3 //匿名类也行 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); 
19 //修改 20 int rusultEdit = conn.Execute("update userinfo set age=25 where username=@username", new { UserName = "user0" }); Model.Show insert = new Model.Show { id = 258, name = "insert", remark = "新增" }; //传对象 conn.Execute("update show set name='update' where id =@id", insert); 
讯享网 //删除 int id = 250; conn.Execute("delete show where id = @id", new { id }); //变量名id必须跟@id匹配。才能映射 23 int resultDel = conn.Execute("delete from userinfo where uid=@uid", new { UId = 6 }); //也可以 //删除也可以传对象 Model.Show insert = new Model.Show { id = 256, name = "71", remark = "新增" }; conn.Execute("delete show where id = @id and name=@name", insert); //也可以 
2、Query方法,返回值为IEnumerable类型
 1   //带参数查询 例子:查询用户名为user1,年龄为20的用户[dapper自动可以Mapper到Object] 2 IEnumerable<UserInfo> query1 = conn.Query<UserInfo>("select * from userinfo where age=@Age and username=@username", new{Age=20,UserName="user1"}) 
讯享网 //in查询 例子:查询年龄是20,21,或22的用户 5 IEnumerable<UserInfo> query2=conn.Query<UserInfo>("select * from userinfo where age in @ages",new {ages=new int [3]{20,21,22}}); 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 * froExecutem 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次 } //返回多个结果集 例子:查询用户列表和角色列表 8 var sql = "select * from userinfo; select * from roleinfo"; 9 var query3 = conn.QueryMultiple(sql);//GridReader类型 10 var usesList = query3.Read<UserInfo>();//IEnumberable类型 11 var roleList = query3.Read<RoleInfo>(); 

可以看到。QueryMultiple 有两种读取方式 ,很方便

var g3 = gridReader.Read<Model.Show>(); //转实体类
var g4 = gridReader.Read(); //基本读取方式

GridReader(网格读者)类型

这里需要注意 的是,参数部分顺序: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
在这里插入图片描述
这里用到了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
执行结果后。你会发现 info 中除了id有值,其余属性是没有获取到值的(i.address本应该有值)
在这里插入图片描述
看下Query方法有个默认值splitOn = “Id”
(ll in this we go right to left through the data reader in order to cope with properties that arel/
named the same as a subsequent primary key that we split on
在这种情况下,我们从右到左通过数据读取器来处理属性,这些属性与我们分割的后续主键相同。)

其实说白了就是:splitOn所采用的方法就是对我们所要获得的属性列表list从右到左进行查找,如果查找到了 splitOn = “Id”中的这个Id属性那么就将list一分为二,左边属于TFirst 右边属于TSecond.


我的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(以属性name进行分割)
修改代码:
在这里插入图片描述
执行结果正确了。info的id没值。是因为select 过滤掉了
在这里插入图片描述


当然。这样仅仅 是两个表join。如果是三个表,或者更多。在项目中还是有的吧,2个以上的表join利用splitOn进行分割就不可取了

可以把多个类整合到一个类下面。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
在这里插入图片描述

表连接查询
讯享网 1 //用户类 2 public class UserInfo 3 { 4 public int UId { get; set; }//用户Id 5 public string UserName { get; set; }//用户名 6 public int Age { get; set; }//年龄 7 public int RoleId { get; set; }//角色Id 8 9 } 10 //角色类 11 public class RoleInfo 12 { 13 public int RId { get; set; }//角色Id 14 public string RoleName { get; set; }//角色名 15 } //表连接查询 例子:查询用户信息和其对应的角色名 14 //1、返回强类型结果 15 var sql2 = @"select u.username,u.age,u.uid ,r.rolename from userinfo as u join roleinfo as r on u.roleid=r.rid"; 16 var result2 = conn.Query<UserInfo, RoleInfo, UserInfo>(sql2, (user, role) => 17 { 18 user.Role = role; 19 return user; 20 }, splitOn: "RoleName");//splitOn参数表示分割,前边的是第一个对象的属性,后边的是第二个对象的属性 21 22 //2、返回动态类型结果 23 var result3 = conn.Query(sql2); 24 foreach (var item in result3) 25 { 26 Console.WriteLine("username:{0},rolename:{1}", item.username, item.rolename); 27 } 
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();

存储过程的crud格式
创建存储过程

使用Transact-SQL语句创建存储过程

Transact-SQL语言使用CREATE PROCEDURE语句创建存储过程,其一般格式为:

讯享网CREATE PROC [ EDURE ] procedure_name [ ;number ] [ @parameter data_type [ = default ],…] AS sql_statement 

说明:

procedure_name:给出存储过程名。

number:为可选的整数,对同名的存储过程指定一个序号

@parameter:为存储过程的形参,@符号作为第一个字符来指定参数名。

data_type:指出参数的数据类型。

default:给出参数的默认值。

sql_statement:存储过程所要执行的SQL语句,它可以是一组SQL语句,可以包含流程控制语句等。

执行存储过程

zTransact-SQL语言使用EXECUTE语句执行存储过程,其一般格式为:

exec dbo.存储过程名 参数值; 

一般在执行存储过程是,最好加上架构名称,例如 dbo.USP_GetAllUser 这样可以可以减少不必要的系统开销,提高性能。 因为如果在存储过程名称前面没有加上架构名称,SQL SERVER 首先会从当前数据库sys schema(系统架构)开始查找,如果没有找到,则会去其它schema查找,最后在dbo架构(系统管理员架构)里面查找。

存储过程的修改和删除

1.修改存储过程Transact-SQL语言使用ALTER PROCEDURE语句修改存储过程,其一般格式为:

大致同创建

讯享网 ALTER PROC [ EDURE ] procedure_name [ ;number ] **[ @parameter data_type [ = default ]********]** AS sql_statement 

2.删除存储过程

Transact-SQL语言使用DROPPROCEDURE语句删除存储过程,其一般格式为:

 ALTER PROC [ EDURE ] procedure_name [ ;number ] **[ @parameter data_type [ = default ]********]** AS sql_statement 

6-5】 删除存储过程score_find

DROP PROCEDURE score_find







.Net调用存储过程
①不需要获取返回值和输出参数

我这里存储过程,就不在编写了,用之前的列子 http://www.cnblogs.com/nsky/p/7766653.html
CommandType.StoredProcedure 标记是存储过程
如果只执行存储过程。不需要获取返回值和输出参数。直接这样既可

讯享网 //不获取输出参数 var  = 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  = 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 1 = 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"); 

执行结果:
在这里插入图片描述
也许你看不明白,这些值的说明。那看看我存储过程的逻辑
在这里插入图片描述

存储过程及触发器

sql servre 帮助文档中对存储过程的解释
  创建存储过程。存储过程是已保存的 Transact-SQL 语句集合,或对 Microsoft .NET Framework 公共语言运行时 (CLR) 方法的引用,
  可接收并返回用户提供的参数。可以创建过程供永久使用,或在一个会话(局部临时过程)中临时使用,或在所有会话(全局临时过程)中临时使用
创建存储过程可以用 proc或者procedure关键字 proc是简写

编写个简单的存储过程,没有任何参数和返回值的存储过程
USE TestInfo GO IF OBJECT_ID('proc_show01','P') IS NOT NULL --存储过程是否存在  DROP PROCEDURE proc_show01 --删除存储过程 GO CREATE PROC proc_show01 AS SELECT * FROM Show 

执行sql语句成功后,在sql中可以看到存储过程已经创建

OBJECT_ID(object_name,'object_type);函数用于判断对象是否存在
object_type对应的类型如下
  AF = Aggregate function (CLR)
  C = CHECK constraint --检查约束
  D = DEFAULT (constraint or stand-alone)
  F = FOREIGN KEY constraint --外键约束
  FN = SQL scalar function --函数
  FS = Assembly (CLR) scalar-function
  FT = Assembly (CLR) table-valued function
  IF = SQL inline table-valued function
  IT = Internal table
  P = SQL Stored Procedure --存储过程
  PC = Assembly (CLR) stored-procedure --CLR存储过程
  PG = Plan guide
  PK = PRIMARY KEY constraint --主键约束
  R = Rule (old-style, stand-alone) --规则
  RF = Replication-filter-procedure
  S = System base table --数据库
  SN = Synonym
  SQ = Service queue
  TA = Assembly (CLR) DML trigger --CLR触发器
  TF = SQL table-valued-function
  TR = SQL DML trigger --DML触发器
  U = Table (user-defined) --数据表
  UQ = UNIQUE constraint --唯一约束
  V = View --视图
  X = Extended stored procedure

讯享网比如上面的判断存储过程是否存在 OBJECT_ID('proc_show01','P') 获取存储过程名为:proc_show01 判断表是否存在 OBJECT_ID('info','U') 获取表名为:info 或者: select * from sysobjects where name='info' and type='u' 

SQL Server支持五种类型的完整性约束
  NOT NULL (非空)–防止NULL值进入指定的列,在单列基础上定义,默认情况下,ORACLE允许在任何列中有NULL值.
  CHECK (检查)–检查在约束中指定的条件是否得到了满足.
  UNIQUE (唯一)–保证在指定的列中没有重复值.在该表中每一个值或者每一组值都将是唯一的.
  PRIMARY KEY (主键)–用来唯一的标识出表的每一行,并且防止出现NULL值,一个表只能有一个主键约束.
  POREIGN KEY (外部键)–通过使用公共列在表之间建立一种父子(parent-child)关系,在表上定义的外部键可以指向主键或者其他表的唯一键.

在.Net转编写测试代码。调用刚创建的存储过程

/// 执行存储过程 /// </summary> /// <param name="cmdText">存储过程的名称</param> /// <param name="param">存储过程参数</param> /// <returns></returns> public static DataTable GetPro2(string cmdText, params SqlParameter[] param) { DataTable dt = new DataTable(); using (SqlConnection conn = new SqlConnection(connStr)) { SqlCommand cmd = new SqlCommand(cmdText, conn); //数据库处理函数命令 // 指定执行语句为存储过程 cmd.CommandType = CommandType.StoredProcedure; if (param != null && param.Length != 0) { cmd.Parameters.AddRange(param); } SqlDataAdapter dp = new SqlDataAdapter(cmd); //填充dataTable dp.Fill(dt); } return dt; } 

在这里插入图片描述

编写一个有输入参数的存储过程
讯享网USE TestInfo GO IF OBJECT_ID('proc_show01','P') IS NOT NULL--存储过程是否存在  DROP PROCEDURE proc_show01 --删除存储过程 GO CREATE PROC proc_show01 ( @name nvarchar(20) ) AS SELECT * FROM Show where @name=Name 

编写存储过程的可空参数,当存储过程参数有默认值的时候,
那么.net在调用存储过程的时候。可以不用传参数。否则如果不传这会报错
所以:
除非定义了参数的默认值或者将参数设置为等于另一个参数,否则用户必须在调用过程时为每个声明的参数提供值

USE TestInfo GO IF OBJECT_ID('proc_show01','P') IS NOT NULL --存储过程是否存在  DROP PROCEDURE proc_show01 --删除存储过程 GO CREATE PROC proc_show01 ( @name nvarchar(20) = null --默认值为空 ) AS IF @name is null begin set @name='刘德华' --当没有传值的时候。设置默认值 end select * from Show where @name = name --测试。当不传值的时候,默认查询的是 “刘德华” 
创建有输入参数和输出参数的存储过程
讯享网USE TestInfo GO IF OBJECT_ID('proc_show01','P') IS NOT NULL--存储过程是否存在  DROP PROCEDURE proc_show01 --删除存储过程 GO CREATE PROC proc_show01 ( @id int output, --输出参数,输出id @name nvarchar(20) = null --默认值为空 ) AS IF @name is null begin set @name='刘德华' --当没有传值的时候。设置默认值 set @id=0 select * from Show where name = @name --return end else begin set @id=(select ID from Show where name = @name) select * from Show where name = @name end 

既然有输出参数。那么得修改上面的.Net代码。如下

/// <summary> /// 调用存储过程 /// </summary> /// <param name="cmdText">存储过程名称</param> /// <param name="v1">输出参数(这里是ID)</param> /// <param name="param">参数</param> /// <returns></returns> public static DataTable GetPro1(string cmdText, out int v1, params SqlParameter[] param) { DataTable dt = new DataTable(); using (SqlConnection conn = new SqlConnection(connStr)) { SqlCommand cmd = new SqlCommand(cmdText, conn); // 指定执行语句为存储过程 cmd.CommandType = CommandType.StoredProcedure; if (param != null && param.Length != 0) { cmd.Parameters.AddRange(param); } SqlDataAdapter dp = new SqlDataAdapter(cmd); //dp.SelectCommand.Parameters.AddRange(param); dp.Fill(dt); /* 获取输出参数。 * 这里在组装参数的时候。指定了数组的第一个数是输出参数 */ v1 = Convert.ToInt32(param[0].Value);           //也可以通过SqlCommand根据参数名称获取存储过程的返回值,跟param[0].Value是同样的效果 object id = cmd.Parameters["@id"].Value; } return dt; } 

在组装参数的时候。要指定哪些参数是输入参数。哪些是输出参数,默认是输入参数(Input)
如果是输入(或者输入输出)参数。则必须要赋值。在存储过程中没有给默认值的情况下
在下图可以看出。有输入参数有两个 Input 和 InputOutput
.Net 有个ParameterDirection 枚举类
在这里插入图片描述

sql 中有out 输出参数,output 输入输出参数

讯享网CREATE PROC proc_show01 ( @id int output, --输入输出参数,输出id @ck int out, @name nvarchar(20) = null --默认值为空 ,默认是输入参数 ) 

测试代码

 static void Main(string[] args) { //SqlParameter p = new SqlParameter("@name", "张三"); //拼装参数 (定义一个参数对象) SqlParameter[] param = { new SqlParameter("@id",SqlDbType.Int), new SqlParameter("@name",SqlDbType.NVarChar) }; //设置参数是输出参数 param[0].Direction = ParameterDirection.Output; param[1].Value = "王五"; int id; DataTable dt = SQLHelper.GetPro1("proc_show01", out id, param); //没有参数 } 

运行看结果
在这里插入图片描述
上面用 param[0].Direction = ParameterDirection.Output; 指定第一个参数是输出参数
然后通过 v1 = Convert*.ToInt32(param[0].Value); 获取存储过程返回的值

从ParameterDirection枚举可以看出输入输出参数都测试过了。还有一个操作的返回值没有测试

有操作类返回值的存储过程
讯享网USE TestInfo GO IF OBJECT_ID('proc_show01','P') IS NOT NULL--存储过程是否存在 DROP PROCEDURE proc_show01 --删除存储过程 GO CREATE PROC proc_show01 ( @id int output, --输出参数,输出id @name nvarchar(20) = null --默认值为空 ) AS /* 定义一个变量,返回一个值 也可以不定义变量,直接用return 返回 */ declare @returnValue int IF @name is null begin set @name='刘德华' --当没有传值的时候。设置默认值 set @id=0 select * from Show where name = @name set @returnValue=10 --return 0 --这里同样可以 end else begin set @id=(select ID from Show where name = @name) select * from Show where name = @name set @returnValue=11 end return @returnValue --返回值 

用 ParameterDirection.ReturnValue 指定是返回值
在这里插入图片描述

GetPro1则要加一个out 参数
public static DataTable GetPro1(string cmdText, out int v1,out int v2, params SqlParameter[] param)
则: v2 = Convert.ToInt32(param[1].Value);

测试看效果
在这里插入图片描述
存储过程里面也可以执行一个新增操作。然后返回刚新增的ID,比如:

begin set @name='刘德华' --当没有传值的时候。设置默认值 --set @id=0 select * from Show where name = @name set @returnValue=10 --return 0 --这里同样可以 insert Show(Name,Remark)VALUES('新增','地球'); set @id = @@IDENTITY --返回新增的ID end 

上面都是通过.net代码访问存储过程,那么通过Transact-SQL语句怎么执行呢?
Transact-SQL 语句用exec(简写)关键字 ,全称是execute关键字
因为存储过程的参数顺序是
在这里插入图片描述
所以可以这样直接传参数,但顺序必须根据存储过程定义参数顺序一样
在这里插入图片描述
上面只是获取结果集。那么怎获取输出参数(outPut)和返回值呢(ReturnValue)
因为返回值是方法的返回值。所以可以变量名=存储过程名称 是不是跟.Net中很相似?

讯享网declare @m int --定义变量接收值 declare @result int exec @result=[proc_show01] @name='赵六',@id=@m output --一定要注名是output select @m as '输出参数',@result as '返回值' 

执行结果
在这里插入图片描述
其实就是参数名= 值 @name=‘赵六’,@id=@m 的方式。因为
一旦使用了 ‘@name = value’ 形式之后,所有后续的参数就必须以 ‘@name = value’ 的形式传递。
用这种方式。顺序可以不用跟存储过程中定义参数的顺序相同
如果不用@name = value’的方式同样可以,
但这样直接传参数,但顺序必须根据存储过程定义参数顺序一样返回值放在最前面

DECLARE @name varchar --set @name='张三' DECLARE @id int DECLARE @result int EXEC @result = proc_show01 @id output,'张三' --这里传参数的顺序一定要对应 --EXEC @result = proc_show01 @id output,@name select @id as '输出参数',@result as '返回值' 

结果一样,其实不一样。因为传的参数不一样,哈哈哈
在这里插入图片描述

使用老师提供的SqlMapperUtil.cs来学习

基于的是控制台

GetMaxID

SqlMapperUtil.cs代码

讯享网 /// <summary> /// return specific table max ID /// 字段名FieldName要符合max()函数的要求 /// </summary> /// <param name="FieldName"></param> /// <param name="TableName"></param> /// <param name="connectionName"></param> /// <returns></returns> public static int GetMaxID(string FieldName, string TableName, string connectionName = null) { string sql = "select max(" + FieldName + ") from " + TableName; using (SqlConnection cnn = GetOpenConnection(connectionName)) { return cnn.Query<int>(sql, null).Single(); //严格返回一个元素项,否则抛出异常 } } 

Program.cs代码

Console.WriteLine(SqlMapperUtil.GetMaxID("sname", "student")); 

InsertSqlWithReturnId

SqlMapperUtil.cs代码

讯享网 //返回新插入行的主键Id值 public static int InsertSqlWithReturnId(string sql, dynamic parms, string connectionName = null) { using (SqlConnection cnn = GetOpenConnection(connectionName)) { return cnn.Query<int>(sql + ";SELECT CAST(SCOPE_IDENTITY() as int);", (object)parms).Single(); //SCOPE_IDENTITY()取得返回在当前会话中的任何表内所生成的最后一个标识值(返回值为十进制(38,0),所以采用强制类型转换) } } 

Program.cs代码

var sql = "insert into Student values(@Sno,@Sname,@Ssex,@Sbirthday,@Sclass)"; int num = SqlMapperUtil.InsertSqlWithReturnId(sql, new { Sno = "118", Sname = "张三", Ssex = "男", Sbirthday = "2022/7/2", Sclass = "研20" }); Console.WriteLine(num); 

Exists

SqlMapperUtil.cs代码

讯享网 public static bool Exists(string sql, dynamic parms, string connectionName = null) { using (SqlConnection cnn = GetOpenConnection(connectionName)) { return cnn.Query<int>(sql, (object)parms).Single() > 0 ? true : false; //cnn.Query()返回值为IEnumerable类型 } } 

Program.cs代码

var sql = "insert into Student values(@Sno,@Sname,@Ssex,@Sbirthday,@Sclass)"; int num = SqlMapperUtil.InsertSqlWithReturnId(sql, new { Sno = "118", Sname = "张三", Ssex = "男", Sbirthday = "2022/7/2", Sclass = "研20" }); Console.WriteLine(num); 
MultipleSql
讯享网 public static int MultipleSql<T>(string sql, IEnumerable<T> entities, string connectionName = null) where T : class, new() { using (SqlConnection cnn = GetOpenConnection(connectionName)) { int records = 0; foreach (T entity in entities) { records += cnn.Execute(sql, entity); } return records; } } 
string multsql = @"select * from Student where Sname=@Sname select * from Student where Sname=@Sname select * from Student where Sname=@Sname" ; var entities =new List<Student> { new { Sname = "李军" } , "李军" , "李军" }; Console.WriteLine(SqlMapperUtil.MultipleSql<Student>(multsql, entities)); 

未理解

SqlWithTransaction
讯享网 public static int SqlWithTransaction(string sql, dynamic parms = null, string connectionName = null) { using (SqlConnection cnn = GetOpenConnection(connectionName)) { int records = 0; //方法一 using (var trans = cnn.BeginTransaction()) { //开启数据库事物 try { records = cnn.Execute(sql, (Object)parms, trans, 30, CommandType.Text); trans.Commit(); //提交事物 } catch (DataException ex) { trans.Rollback(); //事物回滚 throw ex; } } //方法二TransactionScope不一定比方法一好,原因在: http://stackoverflow.com/questions//bulk-inserts-taking-longer-than-expected-using-dapper return records; } } 
var sql = "select * from course"; Console.WriteLine(SqlMapperUtil.SqlWithTransaction(sql)); //demo2 var sql = "update Student set Ssex= '男' where Sno = '108'"; Console.WriteLine(SqlMapperUtil.SqlWithTransaction(sql)); 
StoredProcWithTransaction
讯享网public static int StoredProcWithTransaction(string procname, dynamic parms = null, string connectionName = null) { using (SqlConnection cnn = GetOpenConnection(connectionName)) { int records = 0; //方法一 using (var trans = cnn.BeginTransaction()) { try { records = cnn.Execute(procname, (object)parms, trans, 30, CommandType.StoredProcedure); trans.Commit(); } catch (DataException ex) { trans.Rollback(); throw ex; } } //方法二TransactionScope不一定比方法一好 http://stackoverflow.com/questions//bulk-inserts-taking-longer-than-expected-using-dapper return records; } } 
var parms = new DynamicParameters(); parms.Add("@Sname", "李军"); Console.WriteLine(SqlMapperUtil.StoredProcWithTransaction("getStudentBySname", parms)); //方法2 Console.WriteLine(SqlMapperUtil.StoredProcWithTransaction("getStudentBySname", new{Sname=”李军“})); 
讯享网CREATE PROCEDURE [dbo].[getStudentBySname] @Sname nvarchar(20) AS begin select * from dbo.Student where @Sname=Sname; end go --通过他们的Sname来查找一个特定的用户 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tWSsxfRs-1668686915130)(https://s2.loli.net/2022/10/26/iNdeJPKIOpGft7Z.png)]

ToDataTable
 //由一个list列表得到一个table public static DataTable ToDataTable<T>(this IList<T> list) { PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T)); //获取指定类型组件的属性集合。 DataTable table = new DataTable(); for (int i = 0; i < props.Count; i++) { //创建表格 PropertyDescriptor prop = props[i]; table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType); } object[] values = new object[props.Count]; foreach (T item in list) { //表格中添加数据 for (int i = 0; i < values.Length; i++) values[i] = props[i].GetValue(item) ?? DBNull.Value; table.Rows.Add(values); } return table; } 
讯享网 
GetParametersFromObject
 /// <summary> /// 由一个对象去生成一个动态参数袋 /// </summary> /// <param name="obj"></param> /// <param name="propertyNamesToIgnore"></param> /// <returns></returns> public static DynamicParameters GetParametersFromObject(object obj, string[] propertyNamesToIgnore) { if (propertyNamesToIgnore == null) propertyNamesToIgnore = new string[] { String.Empty }; DynamicParameters p = new DynamicParameters(); //构造一个动态参数袋 PropertyInfo[] properties = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); //GetType() 当前实例的确切运行时类型 foreach (PropertyInfo prop in properties) { if (!propertyNamesToIgnore.Contains(prop.Name)) p.Add("@" + prop.Name, prop.GetValue(obj, null)); } return p; } 
讯享网 
SetIdentity
public static void SetIdentity<T>(IDbConnection connection, Action<T> setId) { dynamic identity = connection.Query("SELECT @@IDENTITY AS Id").Single(); T newId = (T)identity.Id; setId(newId); } 
GetPropertyValue
讯享网 public static object GetPropertyValue(object target, string propertyName) { PropertyInfo[] properties = target.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);//获得当前实例的确切运行时类型的属性组 object theValue = null; foreach (PropertyInfo prop in properties) { if (string.Compare(prop.Name, propertyName, true) == 0) { theValue = prop.GetValue(target, null); } } return theValue; } 
 
小讯
上一篇 2025-04-03 18:31
下一篇 2025-04-04 13:47

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/55099.html