Dapper入门

2023-11-07

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 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");

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

存储过程及触发器

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 --默认值为空 ,默认是输入参数
)

但在.Net都是output。因为output就是输入输出参数的总称
param[3].Direction = ParameterDirection.Output

测试代码

 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/10689779/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/10689779/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;
        }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Dapper入门 的相关文章

随机推荐

  • tq210-kernel 4.1.33移植(1)基本移植

    这篇文章讲述一个新的kernel的移植 1 到kernel org下载4 1 33 修改顶层Makefile ARCH arm CROSS COMPILE arm Linux 根据自己的环境修改交叉编译器前缀 如果发现 tmp cc8nFJ
  • 【Attention机制】YOLOX模型改进之(SE模块、ECA模块、CBAM模块)的添加

    文章目录 YOLOX模型改进 模块简介 SE模块 SE模块的具体介绍 插入位置 主要代码 CBAM模块 插入位置 主要代码 目的动机 ECA模块 插入位置 主要代码 模块添加 建立attention py 修改yolo pafpn py文件
  • 在Macbook Pro上为TensorFlow设置GPU

    最近忽然发现自己的Macbook Pro上装有一块额外的NVIDIA GeForce GT 750M显卡 于是蠢蠢欲动想装一个TensorFlow 试试在GPU上跑算法的性能 先进入TensorFlow官网的Mac安装页面 发现要先装一堆N
  • 循环语句

    for循环 for循环其实本质上与while循环本质上是一样的 标准形式 for 语句1 表达式的初始化 语句2 测试条件 语句3 执行更新 语句内容 关于for循环的结构 语句1是表达式是初始化 只会在程序开始的时候执行一次 语句2是判断
  • EMC测试项分类

    EMC包含两大项 EMI 干扰 和 EMS 敏感度 抗干扰 EMI测试项包括 RE 辐射 发射 CE 传导干扰 Harmonic 谐波 Flicker 闪烁 EMS测试项包括 ESD 静电 EFT 瞬态脉冲干扰 DIP 电压跌落
  • linux 日志 硬件检测,在Linux上分析硬件检测日志

    数据库管理员在数据库的运维过程中或多或少要和操作系统乃至硬件打上交道 分析数据库故障时操作系统日志往往也是一个重要的线索来源 以Linux操作系统为例 其主要的日志子系统 syslog subsystem 可大致分为三类 即1 用户连接日志
  • IKE主模式及预共享密钥认证配置实验

    一 组网和实验环境 按如上的接口ip先作配置 本文实验采用的交换机是H3C模拟器 下载地址如下 http forum h3c com forum php mod viewthread tid 109740 highlight H3C E6
  • L1-018 大笨钟(java)

    1 题目详情 微博上有个自称 大笨钟V 的家伙 每天敲钟催促码农们爱惜身体早点睡觉 不过由于笨钟自己作息也不是很规律 所以敲钟并不定时 一般敲钟的点数是根据敲钟时间而定的 如果正好在某个整点敲 那么 当 数就等于那个整点数 如果过了整点 就
  • kerberos认证系统服务器,基于Kerberos认证的NFS服务器搭建

    NFS是Linux下常用的共享软件 v3版本不太安全 无法进行用户认证 这里简单说明一下V4版本和Kerberos配合实现认证访问的过程 0 准备工作 跟之前的Kerberos一样 需要3台机器来做试验 很多资料上写的是两台 即kdc ni
  • 2022年11月14日--11月25日(ue4 tf1视频教程+socket视频教程+cesium for ue源码抄写,本周10小时,合计1747小时,剩余8253小时)

    工作内容中有高并发 我感觉cesium for ue除了例子外 很难突破 所以把网络视频教程学下 学习不是难事 难的是没有资料 从0到1 目前 mysql 7 1 tf1 4 4 oss 12 1 蓝图反射 1 7 moba 1 5 web
  • 【解决新手爬虫 python3】UnicodeEncodeError: ‘gbk‘ codec can‘t encode character ‘‘ in position

    解决新手爬虫遇到的UnicodeEncodeError gbk codec can t encode character xa0 in position 7084 illegal multibyte sequence 起初的代码 from
  • Qt程序图标

    网络上有很多这方面的介绍 这里只是MARK一下 程序图标说明 准备 1 图标文件 ICO图标文件 也许需要BMP PNG转ICO工具 2 资源文件 RC文件 可手动创建一个空的RC文件 注 这两个文件应与工程文件 PRO 放在同一路径下 步
  • 编写一个函数计算传入字符串中数字、字母、空格以及其它字符的个数

    编写一个函数计算传入字符串中数字 字母 空格以及其它字符的个数 def num str1 a b c d 0 for i in str1 if i isdigit a 1 elif i isalpha b 1 elif i isspace
  • 记录一次生产环境Net Core应用内存暴涨导致OOM的排查过程

    事情起源于某个周五 刚开始是突然发现生产服务不能访问 请求时居然直接提示服务器拒绝响应 然后连用于管理生产环境的Portainer虽然能打开 但登录右上角直接出红色告警信息无法接收服务器信息 进去后所有的node都不显示 生产环境跑了二年多
  • XCTF黑客精神解题报告

    题目来源 https adworld xctf org cn 解题环境 kali frida 12 8 0 Win10 IDA PRO 7 0 整体思路 静态分析 dex 应用的核心思路为com gdufs xman MyAPP类中最先执行
  • 为什么 bindService 能和 Activity 的生命周期联动?

    前言 之前做一道面试题 startService 和 bindService 有什么不同 为什么 bindService 能和 Activity 的生命周期联动 前一个问题可以很快回答出来 生命周期不同 结束方式不同 交互方式不同 后一个问
  • java实现批量更新数据_java批量更新数据库

    String queries INSERT INTO Employee Eno Ename Ecode EDept values 1 Allen abc Sales INSERT INTO Employee Eno Ename Ecode
  • 在零配置的情况下,怎么启动、打包一个.vue文件?

    问题 比如我们在开发一个组件 以及做一些小demo的时候 怎么快速启动服务 解决 1 安装拓展 npm install g vue cli service global 复制代码 2 新建vue文件 建立一个vue test文件夹 在里面新
  • npm、yarn 与 pnpm 的逻辑区别

    目录 npm2的依赖管理 npm3 yarn的依赖管理 pnpm的依赖管理 npm2的依赖管理 npm2 安装依赖的时候比较简单直接 直接按照包依赖的树形结构下载填充本地目录结构 比如在项目中A和 C 都依赖 B 无论被依赖的 B 是否是同
  • Dapper入门

    Dapper 一 dapper是什么 dapper是一款轻量级的ORM Object Relationship Mapper 它负责 数据库和编程语言之间的映射 SqlConnection MysqlConnection OracleCon