前言

  这两天看园子里有个朋友写Dapper的拓展,想到自己之前也尝试用过,但不顺手,曾写过几个方法来完成自动的Insert操作。而对于Update、Delete、Select等,我一直对Dictionary<string,object>参数类型有很深的感情,旨在页面传递的条件基本上都是Json,很容易用字典类型存储,想过在遵循某种命名规则的前提下,自动完成查询,简单的业务,直接能得到相应条件的数据,为此研究过一段时间,如果需要详细的了解,请看这里:

  理想中的SQL条件拼接方式

  理想中的SQL条件拼接方式(二)

  看了下文章的时间,吓我一条,居然在2个月前,事实上,这个念头在心里也一直有很长时间了,却觉得自己很难去处理好它,封装的没问题,但用起来特别不顺手。如今新年来临,再来挑战自己。

  之前遇到的最大的问题就是处理值与类型的映射。由于页面传递的是Json数据源,后来序列化成Dictionary<string,object>后,很多类型就丢失了。如直接引起程序错误的DateTime类型了。原来的处理方式是各种手动的映射,更改数据类型,再提交ado.net操作。

  如今查看Poto这个Orm的源代码,它在实体增删改的时候将类型缓存起来,而且还有该类型的属性,在使用的时候,做过几次转换,而我像发现新大陆似得,觉得这完全可以解决我的问题呀。于是照搬了它的缓存部分代码,并结合Dapper实现了实体的增删改查,当然查询是通过Dictionary的传参。

对Dapper和Poto的拓展与修改

  1.在Dapper的1219行代码处有方法 GetCacheInfo,在其中增加IDictionary参数支持。修改后的方法为:

        private static CacheInfo GetCacheInfo(Identity identity)
{
CacheInfo info;
if (!TryGetQueryCache(identity, out info))
{
info = new CacheInfo();
if (identity.parametersType != null)
{
if (typeof(IDynamicParameters).IsAssignableFrom(identity.parametersType))
{
info.ParamReader = (cmd, obj) => { (obj as IDynamicParameters).AddParameters(cmd, identity); };
}
#if !CSHARP30
else if ( //支持传递Dictionary<K,V>为参数
typeof(IDictionary).IsAssignableFrom(identity.parametersType) ||
typeof(IEnumerable<KeyValuePair<string, object>>).IsAssignableFrom(identity.parametersType)
&& typeof(System.Dynamic.IDynamicMetaObjectProvider).IsAssignableFrom(identity.parametersType)
)
{
info.ParamReader = (cmd, obj) =>
{
IDynamicParameters mapped = new DynamicParameters(obj);
mapped.AddParameters(cmd, identity);
};
}
#endif
else
{
info.ParamReader = CreateParamInfoGenerator(identity, false);
}
}
SetQueryCache(identity, info);
}
return info;
}

GetCacheInfo

  2.在Poto中,增加了OrderAttribute,定义在实体上,指定自动生成的Select排序规则。

再谈Orm的具体实现

  基于实体的增删改,参数是object,则可以根据对象获取到它的类型、属性,还有定义在类上的Attribute。很容易就可以构造出 insert、update、delete。另外由于Dapper支持一次SQL,在多个对象上执行,我对方法做了这样的改进,以充分利用Dapper。解释下,一次SQL,在多个对象上执行,如批量Insert,批量Update,批量Delete。SQL语句使用参数化,则是同一条,执行时参数来自于不同的对象而已。所以增删改查,参数为object时,还可以传递List、数组等。

  在Update和Delete方法中,我还希望通过条件来操作,运用到上面说的基于命名规则拼接SQL的方式,当然Select操作也不例外。主要实现代码:

        private readonly Regex reg = new Regex(@"^(?<tab>\w+\.)?(?<Pre>(PK|Begin|End|Like|UnLike|Null|In))?(?<Key>\w+)$");

        private string CreateWhere(PocoData t, IDictionary<string, object> condition)
{
var sql = new StringBuilder(); //遍历条件
foreach (var key in condition.Keys.ToArray())
{
var match = reg.Match(key); //正则获取到属性对应的字段名
var pre = match.Groups["Pre"].Value;//获取命名规则中的比较谓词
var colName = match.Groups["Key"].Value;//获取字段名称
//if (string.IsNullOrEmpty(tableName))
// tableName = match.Groups["tab"].Value;//获取字段表名限定 var paraName = string.Format("{0}{1}", pre, colName);//获取该条件被分配的过程参数名 var value = condition[key]; //拼接Sql语句
sql.AppendFormat(" {0} AND",
Builder(pre, colName, paraName, t.TableInfo.TableName, value));//拼接SQL条件 if (pre == "In") //In拼接没有使用过程参数,直接拼接了,将参数从字典中移除
{
condition.Remove(key);
continue;
} //若该字段值的类型为字符串,检测实体中的类型
if (value.GetType() == typeof(string))
{
PocoColumn prop;
if (!t.Columns.TryGetValue(colName, out prop))
throw new Exception(string.Format("can't find any property in object.propertyName:{0},object:{1}", key, t.TableInfo.TableName)); if (prop.PropertyInfo.PropertyType != typeof(string))
condition[key] = prop.ChangeType(value);
}
} if (sql.Length > ) sql.Length -= ;
return sql.ToString();
}

正则拆分SQL

 说到这里,有个小插曲,我发现当我在SQL和Oracle下测试成功后,我传递的Dictionary,并没有指定参数符号,如@或者: 。最后执行的DbCommand对象使用的参数名当然也没有,可居然没有出现任何问题。不知道该怎么解释。这里Sql的库使用的System.Data.SqlClient, net4.0 。而Oracle是使用的官方的,Oracle.ManagedDataAccess.dll ,net4.0。如果有朋友知道,还请告知一二。虽然我想偷懒,但这种突如其来的幸福,还是警惕下。

  最后在Update方法上增加参数,指定更新的列。

其他

  解释下什么是基于单表的Orm。单表操作,增删改查,所有的方法都是在同一个表或者实体上。由于目前我还没有看Dapper或者Poco在多表下是怎么操作的,而暂时我又需要紧急的使用在项目中,因为我不想在写增删改查,简单业务下linq式的查询我也不想写。好吧,我承认我有点鲁莽,不稳定的东西就投入使用,可实践就是检验真理的唯一标准啊。说到实践,关于Poto这个Orm,我看其他人的介绍,经过各种测试,当我用了,我只想说,这测试不仔细,Oracle下各种错误,连自动分页都是错的。

  写到这里,发现具体的实现方式,已然不值一提。在写之前,各种困难,写之后,想要介绍它的时候,发现太简单,没什么可说的。代码中有一点注释,想看的朋友如果看不明白可以咨询。

  先贴下封装后的调用方式。

            var db = new DbHelp(Program.facotry, Program.connStr);

            //增/////////////////////////////////////////////////////////////////////
var tabAdd = new tab1()
{
Name = "ggggg",
Home = "jjjjjj"
};
var row = db.Add(tabAdd);
//批量增
var tabAddArrary = new tab1[] {
new tab1()
{
Name = "批量增1",
Home = "批量增1"
},
new tab1()
{
Name = "批量增2",
Home = "批量增2"
}};
row = db.Add(tabAddArrary); //改//////////////////////////////////////////////////////////////////////////
var tabUpdate = new tab1()
{
Name = "fffffff",
Home = "fffffff",
ID =
};
row = db.Update(tabUpdate);
//批量改
var tabUpdateArrary = new tab1[] {
new tab1()
{
Name = "批量改1",
Home = "批量改1",
ID=
},
new tab1()
{
Name = "批量改2",
Home = "批量改2",
ID=
}};
row = db.Update(tabUpdateArrary);
//条件修改
//1 定义要修改的内容
var dic = new Dictionary<string, object>();
dic["Home"] = DateTime.Now.ToString() + ":修改了";
//定义条件 这里使用了命名规则
var condtion = new Dictionary<string, object>();
condtion["InID"] = "1,3,5";
row = db.Update<tab1>(dic, condtion); //删除///////////////////////////////////////////////////
var tabDelete = new tab1() { ID = };
db.Remove(tabDelete);
//条件删除
var dicDelete = new Dictionary<string, object>();
dicDelete["BeginID"] = ;
row = db.Remove<tab1>(dicDelete); //查询/////////////////////////////////////////////////////
var dicQuery = new Dictionary<string, object>();
dicQuery["EndID"] = ;
var qtab1 = db.Query<tab1>(dicQuery); //分页///////////////////////////////////////////////////////////
int count;
var dicPage = new Dictionary<string, object>();
dicPage["BeginID"] = ;
dicPage["EndID"] = ;
var qtabPage = db.Query<tab1>(dicQuery, , , out count);

封装后的调用

  测试代码下载

  最后祝大家马上有钱。

也来写写基于单表的Orm(使用Dapper)的更多相关文章

  1. 单表操作ORM

    博客园 首页 新随笔 联系 管理 订阅 随笔- 0  文章- 339  评论- 29  Django基础五之django模型层(一)单表操作   本节目录 一 ORM简介 二 单表操作 三 章节作业 ...

  2. 单表ORM框架

    基本描述 1.首先是一个单表的ORM框架,多表连接查询请使用视图或者使用SqlHelper查询,然后转换成实体集合. 2.目前仅完成基本结构和MySQL部分. 3.目前欠缺Lambda表达式解析,所以 ...

  3. 一步步学Mybatis-实现单表情况下的CRUD操作 (3)

    今天这一章要紧接上一讲中的东西,本章中创建基于单表操作的CRUD与GetList操作,此示例中以Visitor表为范例,为了创建一点测试数据我们先弄个Add方法吧 继续在上次的IVisitorOper ...

  4. web框架开发-Django模型层(1)之ORM简介和单表操作

    ORM简介 不需要使用pymysql的硬编码方式,在py文件中写sql语句,提供更简便,更上层的接口,数据迁移方便(有转换的引擎,方便迁移到不同的数据库平台)…(很多优点),缺点,因为多了转换环节,效 ...

  5. ORM简介 单表添加修改删除表记录

    ---------------------------------------------------------------目标既定,在学习和实践过程中无论遇到什么困难.曲折都不灰心丧气,不轻易改变 ...

  6. $Django 模板层(模板导入,继承)、 单表*详(增删改查,基于双下划线的查询)、static之静态文件配置

    0在python脚本中使用django环境 import osif __name__ == '__main__':    os.environ.setdefault("DJANGO_SETT ...

  7. ORM 简介 单表操作

    cls超 Django基础五之django模型层(一)单表操作 本节目录 一 ORM简介 二 单表操作 三xxx 一 ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型 ...

  8. Django中模型层中ORM的单表操作

    ORM概念: MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员 ...

  9. ORM之单表操作

    ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的 ...

随机推荐

  1. [回文树][BZOJ2160][国家集训队]拉拉队排练

    题面 Description 艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了.拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛.所以作为拉拉队队长的楚雨荨同学知道,帮助篮 ...

  2. EF实体部分更新的问题

    之前遇到只更新部分的问题:如前端修改用户信息(不修改密码),传实体到后台,这个实体是没有密码,这样一来要更新的话,得先去数据库通过传过来的实体的ID读取这条记录,然后将改动的部分填到查出来的记录中,再 ...

  3. Weblogic Linux jar包安装

    环境/工具: 系统:CentOS 7 JDK:Oracle JDK fmw_12.2.1.2.0_wls.jar 0x01.新建普通用户weblogic 在Linux环境下建议使用普通用户安装,web ...

  4. 2753: [SCOI2012]滑雪与时间胶囊

    2753: [SCOI2012]滑雪与时间胶囊 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 2633  Solved: 910 Descriptio ...

  5. sourceInsight *** more bytes are required

    现象:用sourceinsight修改的文件无法保存,提示 No enough space to save "XXX", xxx more bytes are required. ...

  6. web开发学习之路是否有尽头

    Linux/Git/Pip/Npm/Composer Apache/Ngnix Mysql/MongoDb/Redis PHP/Python/NodeJS javascript/jQuery/Expr ...

  7. 跟着学!教你开发第一个Java程序

    今天我们的目标是开发人生中的第一个Java程序,虽然可能会很简单,但是这小小的一步却是跨入IT行业的一大步!下面我们来一起来仔细的了解开发的流程. 准备工作 1,作为一名准程序猿自备一台电脑那是必不可 ...

  8. 《Cracking the Coding Interview》——第8章:面向对象设计——题目9

    2014-04-23 23:57 题目:如何设计一个内存文件系统,如果可以的话,附上一些代码示例. 解法:很遗憾,对我来说不可以.完全没有相关经验,所以实在无从入手.这题目应该和工作经验相关吧? 代码 ...

  9. phpStorm9.0 +xampp+chrome php调试环境配置!

    不多说,直接上step by step: 1.xampp配置 看看我的XAMPP版本: 修改配置文件,该打开打开,该加上加上,结果如下(当前需要重新启动apache,配置才会生效): [XDebug] ...

  10. 【多线程学习(2)】继承Thread类和实现Runnable接口、Callable接口的区别

    1)Runnable和Callable同是接口 * Callable的任务执行后可返回值,而Runnable的任务是不能返回值(是void);call方法可以抛出异常,run方法不可以 * 运行Cal ...