一、前言与C#等高级语言的调试相比,调试SQL是一件痛苦的事情。尤其是那些几千行的存储过程,更是我码农的噩梦。将几千行存储过程的SQL分解成C#管理后,调试也有问题。如何让调试更顺畅?请参考后续2.常用调试2.1通常在Dapper中下断点,抓到类似如下SQL:SELECTa.*FROMdbo.ptypeaINNERJOINdbo.PType_PricebONa。typeId=b.PTypeIDLEFTJOINdbo.PType_UnitscONa.typeId=c.UnitsIdWHEREa.typeId=@typeidANDa.CreateDate=@AreaANDpreprice1=@preprice1ANDdeleted=@deleted各种@符号调试前需要手动替换(麻烦),如果能抓到最后的SQL2.2幸运的是,你可以使用SQLServerProfiler来捕获最终的SQL。但是生产环境中的SQLServer并发执行了很多SQL。上图可以看到,在大量的SQL中查找刚刚执行的SQL很麻烦,即使可以按Ctrl+F调出搜索框进行搜索,也得想个好的关键字要搜索,麻烦。3、解决方案既然我们要的是最终的SQL,那为什么不丢给Dapper去执行呢,已经是最后的SQL了,工具代码:publicclassSqlHelper{publicDictionaryParam=newDictionary();publicstringReplaceParam(refstringsql){if(Param.Count==0){returnsql;}StringBuildersb=newStringBuilder();sb.Append(sql);foreach(variteminParam){varparamName=item.Key;varparamValue=item.Value;vartype=paramValue.GetType();if(type==typeof(string)||type==typeof(DateTime)){//字符串sb.Replace($"@{paramName}",$"'{paramValue}'");}elseif(type==typeof(bool)){//bool类if(paramValue.ToString()=="True"){sb.Replace($"@{paramName}","1");}else{sb.Replace($"@{paramName}","0");}}else{//数值sb.Replace($"@{paramName}",paramValue.ToString());}}sql=sb.ToString();returnsql;}}调用示例:publicIEnumerableGetPtypeDetail(){varsql=@"SELECTa.*FROMdbo.ptypeaINNERJOINdbo.PType_PricebONa.typeId=b.PTypeIDLEFTJOINdbo.PType_UnitscONa.typeId=c.UnitsIdWHEREa.typeId=@TypeidANDa.CreateDate=@CreateDateANDpreprice1=@preprice1ANDdeleted=@deleted";varsqlHelper=newSqlHelper();sql.Add(".Typeid","001");sqlHelper.Param.Add("CreateDate",DateTime.Now);sqlHelper.Param.Add("preprice1",3.62M);sqlHelper.Param.Add("deleted",true);sqlHelper.ReplaceParam(refsql);IEnumerableplist=newList();using(varcon=SQLServerHelper.GetConnection()){plist=con.Query(sql);}returnplist;}丢给Dapper执行的SQL永远是最终的SQL,不用费心去抓它。PS:可能有人会质疑这个替换的效率,测试不用担心,C#的字符串替换是很快的,上面的调用例子,当时的测试结果是微妙的纳秒级,有兴趣的看官可以再测试一下。4.***现在丢给Dapper执行的不再是满是@parameters的SQL,而是一个替换的finalSQL。就这样,当老大在远处喊你:小江,你有XX虫,赶紧来看看。您可以在DapperQuery中设置断点,将鼠标放在SQL变量上,不慌不忙,轻松得到最终的SQL进行调试,而不是手动替换@参数,或者在SQLServerProfiler中大海捞针!!!