之前ORM比较火热,自己也搞了个WangSql,但是感觉比较low,大家都说Dapper性能好,所以现在学习学习Dapper,下面简单从宏观层面讲讲我学习的Dapper。
再了解一个东西前,先得学会使用,我也不再赘述怎么使用,接转一个文章吧
http://www.cnblogs.com/yankliu-vip/p/4182892.html
好就当学习了吧,该去看看源码了,到底怎么实现和好在哪呢。
先上一张图,已经把SqlMapper.cs按类拆分了,同时我自己在学习过程中也删了加了改了一些类。
当然最重要的类还是SqlMapper.cs这个类,那就开始吧。
本来想把这个SqlMapper.cs类代码全部粘贴的发现太长了,就算了吧,就把一些关键代码粘贴过来。
private static CacheInfo GetCacheInfo(Identity identity)
{
CacheInfo info;
if (!TryGetQueryCache(identity, out info))
{
info = new CacheInfo();
if (identity.parametersType != null)
{
if (typeof(string).IsAssignableFrom(identity.parametersType))
{
info.ParamReader = delegate(IDbCommand cmd, object obj) { (new StringParameters() as IDynamicParameters).AddParameters(cmd, identity, obj); };
}
else if (typeof(IDictionary).IsAssignableFrom(identity.parametersType))
{
info.ParamReader = delegate(IDbCommand cmd, object obj) { (new DictionaryParameters() as IDynamicParameters).AddParameters(cmd, identity, obj); };
}
else
{
info.ParamReader = CreateParamInfoGenerator(identity);
}
}
SetQueryCache(identity, info);
}
return info;
}
来来来,划重点了 info.ParamReader = CreateParamInfoGenerator(identity); 看到没,这货是干嘛的啊,哪里用的呢?
就这里用的,其实就是那是一个委托,主要用来创建Command的DataParameter的,不信看下面
private static IDbCommand SetupCommand(IDbConnection cnn, IDbTransaction transaction, string sql, Action<IDbCommand, object> paramReader, object obj, int? commandTimeout, CommandType? commandType)
{
var cmd = cnn.CreateCommand();
var bindByName = GetBindByName(cmd.GetType());
if (bindByName != null) bindByName(cmd, true);
cmd.Transaction = transaction;
cmd.CommandText = FormatSql(sql);
if (commandTimeout.HasValue)
cmd.CommandTimeout = commandTimeout.Value;
if (commandType.HasValue)
cmd.CommandType = commandType.Value;
if (paramReader != null)
{
paramReader(cmd, obj);
}
return cmd;
}
又划重点了, paramReader(cmd, obj); 这里就是执行委托创建Command的DataParameter了。
如果有人问为什么要这个呢,那就是你上面连Dapper基本使用都没看啊,滚回去看看先。
举个例子:
sql = "insert into Teacher(Id,Name) values(@Id,@Name)";
string tid = Guid.NewGuid().ToString();
teacher = new Teacher()
{
Id = tid,
Name = "wang"
};
intResult = SqlMapper.Execute(conn, sql, teacher);
这里 SqlMapper.Execute(conn, sql, teacher); 参数teacher就是上面 paramReader(cmd, obj);对应的参数obj,这个委托呢就是将自定义实体teacher变成cmd的Parameters。
那么你又要问了,怎么变的?额,这么嘛就是难点了....
回到上面看看,委托的创建 info.ParamReader = CreateParamInfoGenerator(identity);
关键点也是难点啊同学们CreateParamInfoGenerator这个方法是干嘛的啊,就是创建委托的啊,你个白痴。
好了,方法给你了,自己看吧,注释写的多详细的啊。恩....
WTF,英文的啊,不要紧有翻译的,反正自己看吧,我来给你讲怕误人子弟啊。
就我删减后的Dapper 来说入参解析部分其实就到此结束,什么鬼,毫无亮点,要你讲有何用。
别急,别急,下面讲讲我修改部分。
使用中,我发现参数的这么写 insert into Student(Id,Name,Tid) values(@Id,@Name,@Tid) 那如果我换了数据库比如MySql又得改@为?,换成Oracle又得把@改成:,这是我不能忍受的其一。
使用中,我发现 sql = "delete from Student where Id=#Id#"; intResult = SqlMapper.Execute(conn, sql, "jkajskajsk"); 报错,为毛啊,连字符串入参传入你都不认识,这是我不能忍受其二。
以上问题,可能是我版本问题,我用的是Dapper NET2.0版本。
不管为什么,先解决这个两个痛点。
问题一:
原因分析,主要是不知道数据库类型造成的。
解决办法,那我就提前告诉你,数据库相关信息,我们采用一种驱动方式来设置数据库相关信息。
我新建了个类DbProvider.cs
internal class DbProvider{ public bool UseParameterPrefixInSql { get; set; }
public bool UseParameterPrefixInParameter { get; set; }
public string ParameterPrefix { get; set; }}
很简单,后期你可以自己扩展, ParameterPrefix 这个就是数据库参数前缀,比如@ ? :
//dbProvider
dbProvider = new DbProvider()
{
UseParameterPrefixInSql = true,
UseParameterPrefixInParameter = true,
ParameterPrefix = "@"
};
在SqlMapper创建一个 dbProvider 构造函数里面 对其初始化,具体值最好写在web.config里面,初始化的时候去读配置文件。
有了这个之前的SQL我们可以改改了 insert into Student(Id,Name,Tid) values(#Id#,#Name#,#Tid#)当然原来的写法也是支持的,只不过现在这种写法,保证的SQL参数的统一性,以后切换数据库也容易多了。
可是这样写了,能正常运行吗?答案是NO,所以还需要下面的方法。
//我写的
internal static string FormatNameForSql(string parameterName)
{
return dbProvider.UseParameterPrefixInSql ? (dbProvider.ParameterPrefix + parameterName) : parameterName;
}
internal static string FormatNameForParameter(string parameterName)
{
return dbProvider.UseParameterPrefixInParameter ? (dbProvider.ParameterPrefix + parameterName) : parameterName;
}
internal static string FormatSql(string sql)
{
Regex regex = new Regex("#([a-zA-Z0-9_]+?)#", RegexOptions.IgnoreCase | RegexOptions.Multiline);
var ms = regex.Matches(sql);
foreach (Match item in ms)
{
sql = sql.Replace(item.Value, FormatNameForSql(item.Groups[1].Value));
}
return sql;
}
主要是这个方法 FormatSql 什么时候调呢,在这里
好了,问题一,反正是解决了,下面看看问题二了。
问题二:
原因分析,
来来来,划重点了 info.ParamReader = CreateParamInfoGenerator(identity); 看到没,这货是干嘛的啊,哪里用的呢?
就这里用的,其实就是那是一个委托,主要用来创建Command的DataParameter的
引用的上面的,那个委托啊CreateParamInfoGenerator不支持String、Dictionary这种入参造成的。
解决办法,既然那个委托不支持,我就给不同的类型创建不同的委托就行了啥。
我为继承string类型的创建了一个委托,委托是执行StringParameters实例的AddParameters方法。
我为继承IDictionary类型的创建了一个委托,委托是执行DictionaryParameters实例的AddParameters方法。
通过不同的委托就能实现不同入参实现给Command的Parameters创建赋值了,哈哈哈哈哈....当然你要实现int double ...都一样的方法,加个类继承IDynamicParameters即可。
现在这样子都可以正常使用了
sql = "delete from Student where Id=#Id#";
intResult = SqlMapper.Execute(conn, sql, "jkajskajsk");
sql = "delete from Student where Id=#Id# and Name=@Name and Name=@Name1";
Hashtable dic = new Hashtable();
dic.Add("Id", "123");
dic.Add("Name", "s1234");
dic.Add("Name1", "d12345");
intResult = SqlMapper.Execute(conn, sql, dic);
总结:
这篇文章只是对Dapper入参进行的分析,出参还没看呢,先这样吧,有空再说.
原文地址:http://www.cnblogs.com/deeround/p/6612213.html
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注