postgre 查询表是否存在 dapper_Dapper的正确使用姿势

本文demo适用于MySQL

优点

高性能、易排查、易运维、灵活可控

缺点

和EF相比,手写sql当修改表结构不易发现bug。
习惯了EF后再来使用Dapper,会很难适应那种没有了强类型的安全感。不过可以用单元测和心细来避免。

问题:IDbConnection需不需要手动Open打开连接
答案:有时候需要有时候不需要

Dapper连接可分两种:主动管理(自己管理连接的打开和关闭)和自动管理(自动管理连接的打开和关闭)



bool wasClosed = cnn.State == ConnectionState.Closed;
...
if (wasClosed) cnn.Open();
...
if (wasClosed) cnn.Close();

源码位置 https://github.com/StackExchange/Dapper/blob/master/Dapper/SqlMapper.cs#L530

Note:ADO.NET默认是启用连接池的 Pooling = true,连接池中最大连接数,默认为100

在使用Dapper的过程中,你有可能遇到过连接池超过最大限制。那问题是怎么来的呢?
如果主动管理或者自动管理连接都不会有问题。就怕你管理一半,打开不关闭:


DBContext dBContext2 = new DBContext();
dBContext2.DbConnection.Open();

解决办法相信不用我说了。

Note:在使用事务的时候需要手动打开连接,请不要忘记在catch里面Close。

批量新增


DbConnection.Execute(sqlStr, ListEntity);

insert into tt (a,b,c,d) values (50,1,'1','1'), (51,2,'1','2');

var sql = insert into tt (a,b,c,d) values (@a1,@b1,@c1,@d1), (@a2,@b2,@c2,@d2);
DynamicParameters dynamicParameters = new DynamicParameters();
dynamicParameters.Add("a1","value");
dynamicParameters.Add("b1","value");
dynamicParameters.Add("c1","value");
dynamicParameters.Add("a2","value");
dynamicParameters.Add("b2","value");
dynamicParameters.Add("c2","value");
dynamicParameters.Add("d2","value");
DbConnection.ExecuteScalar<int>(sql, dynamicParameters)

批量修改

//1、可通过匿名对象集合进行参数化数据修改。(需要修改的值都不一样的情况下,性能优化参考4)
DbConnection.Execute(sqlStr, ListEntity);
//2、如果需要修改的值都是一样,只是条件不一样。(使用SQL语句中的IN语法)
DbConnection.Execute("UPDATE tt SET aa = @aa where bb in @bb;", new { aa, bb });
//3、快速批量修改(此方法非常适合`新增或修改`数据的场景,可通过建联合唯一索引来实现新增或修改的区分。【组合字段不能为空,否则为空 不做唯一,有重复空数据】)
insert into test_tbl (id,dr) values (1,'2'),(2,'3'),...(x,'y') on duplicate key update dr=values(dr);
//4、参数化防sql注入
var sql = insert into test_tbl (id,dr) values (@id1,@dr1),(@id2,@dr2),...(@idn,@drn) on duplicate key update dr=values(dr);
DynamicParameters dynamicParameters = new DynamicParameters();
dynamicParameters.Add("id1","value");
dynamicParameters.Add("dr1","value");
dynamicParameters.Add("id2","value");
dynamicParameters.Add("dr2","value");
...
dynamicParameters.Add("idn","value");
dynamicParameters.Add("drn","value");
DbConnection.ExecuteScalar<int>(sql, dynamicParameters)

批量删除

同理,也可以使用参数化和IN语法

查询第一条数据

dBContext.DbConnection.QueryFirstOrDefault("SELECT * from itemfcl_temp limit 1;");    
dBContext.DbConnection.QueryFirstOrDefault("SELECT * from itemfcl_temp;");
dBContext.DbConnection.Query("SELECT * from itemfcl_temp;").FirstOrDefault();
dBContext.DbConnection.Query("SELECT * from itemfcl_temp;").ToList().FirstOrDefault();

If扩展方法

使用过Mybatis的同学都知道,在xml里面写if、else还是蛮好用的。虽然我还是不喜欢在xml里面写sql。
那么在Dapper里面是不是也能简便操作,答案是肯定的。这就得庆幸C#牛逼的语法了。

public static class StringExtension
{
public static string If(this string str, bool condition){
return condition ? str : string.Empty;
}
}

然后我们的sql就可以这样拼接了

left join MaintenanceTemplates it on it.Id = m.MaintenanceTemplateId
where m.IsDeleted = 0
{" and m.Code = @KeyWord ".If(!string.IsNullOrWhiteSpace(input.KeyWord))}
{" and m.ProjectId = @ProjectId ".If(input.ProjectId.HasValue)}
{" and a.ProductId = @ProductId ".If(input.ProductId.HasValue)}

比起以前又臭又长的if判断,个人感觉好多了。

Note:Dapper不会因为传多了参数而报错,所以放心使用If。

使用EF的时候很方便做事务处理,而在Dapper中貌似就没那么优雅了。
我们每次在事务逻辑开始前都需要BeginTransaction开启,事务结束后都需要CommitTransaction提交。代码看起来也就稍显混乱。
如果我们通过特性标记的方式,在标记了UnitOfWork特性的方法自动开启和提交事务那就完美了。如下:

[UnitOfWork]
public virtual void Test(){

}

当然,这是可行的。通过AOP拦截,在方法执行前开启事务,在方法执行后提交事务就可以了。
实现如下:
需要Nuget包Autofac.Extensions.DependencyInjection Autofac.Extras.DynamicProxy

[UnitOfWork]
public virtual void DelUser(){
var sql = "select * from UserTemp";
var userList = dBContext.DbConnection.Query<object>(sql);

var sql2 = $@"INSERT into UserTemp VALUES(0,'{DateTime.Now.ToString()}','sql2执行成功')";
dBContext.DbConnection.Execute(sql2);
throw new Exception("主动报错");

var sq3 = $@"INSERT into UserTemp VALUES(0,'{DateTime.Now.ToString()}','sq3执行成功')";
dBContext.DbConnection.Execute(sq3);
}
public class UnitOfWorkIInterceptor : IInterceptor
{
private DBContext dBContext;
public UnitOfWorkIInterceptor(DBContext dBContext){
this.dBContext = dBContext;
}
public void Intercept(IInvocation invocation){
MethodInfo methodInfo = invocation.MethodInvocationTarget;
if (methodInfo == null)
methodInfo = invocation.Method;

UnitOfWorkAttribute transaction = methodInfo.GetCustomAttributes(true).FirstOrDefault();if (transaction != null && dBContext.Committed)
{
dBContext.BeginTransaction();try
{
invocation.Proceed();
dBContext.CommitTransaction();
}catch (Exception ex)
{
dBContext.RollBackTransaction();throw;
}
}else
{
invocation.Proceed();
}
}
}

完整的测试源码,会在文末提供。

使用EF的同学应该很多人都知道MiniProfiler,我在前些年分享EF的时候有做过简单介绍。
那么我们在执行Dapper的时候是不是也可以对生成的sql做检测和性能监控。
答案是肯定的。Git地址c7965c38a0dba231228146badd0d4896.png

MiniProfiler监控套件还真不是一般的强。EF、MongoDB、MySql、Redis、SqlServer统统支持。
接下来我们实现对Dapper监控,导入Nuget包MiniProfiler.AspNetCore

public class ActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){
var profiler = MiniProfiler.StartNew("StartNew");
using (profiler.Step("Level1"))
{

await next();
}
WriteLog(profiler);
}

private void WriteLog(MiniProfiler profiler){
if (profiler?.Root != null)
{
var root = profiler.Root;
if (root.HasChildren)
{
root.Children.ForEach(chil =>
{
if (chil.CustomTimings?.Count > 0)
{
foreach (var customTiming in chil.CustomTimings)
{
var all_sql = new List<string>();
var err_sql = new List<string>();
var all_log = new List<string>();
int i = 1;
customTiming.Value?.ForEach(value =>
{
if (value.ExecuteType != "OpenAsync")
all_sql.Add(value.CommandString);
if (value.Errored)
err_sql.Add(value.CommandString);
var log = $@"【{customTiming.Key}{i++}】{value.CommandString} Execute time :{value.DurationMilliseconds} ms,Start offset :{value.StartMilliseconds} ms,Errored :{value.Errored}";
all_log.Add(log);
});





}
}
});
}
}
}
}

运行效果:0254929107c1b149d206109849158c4a.png

完整的Demo源码:https://github.com/zhaopeiym/BlogDemoCode/tree/master/Dapper_Demo/DapperDemo

最后给大家推荐一个开源项目quartzui:https://github.com/zhaopeiym/quartzui
基于Quartz.NET 3.0的web管理界面,开箱即用。也可以完美运行在树莓派上。

docker run -v /fileData/quartzuifile:/app/File  --restart=unless-stopped --privileged=true --name quartzui -dp 5088:80 bennyzhao/quartzui:RaspberryPi  

运行在普通PC或云主机上

docker run -v /fileData/quartzuifile:/app/File  --restart=unless-stopped --privileged=true --name quartzui -dp 5088:80 bennyzhao/quartzui  

新建QQ群工控物联:995475200

原文地址:https://www.cnblogs.com/zhaopei/p/dapper.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 0a82388fe9d7f367c421c6aad83ae6ff.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值