经过一番深思熟虑,决定先用Dapper吧.....

以下是我感觉比较有用的一些东西

Dapper项目地址  https://github.com/StackExchange/dapper-dot-net

初次接触Dapper,简单的范例  https://github.com/xliang/dapper-net-sample

园子里树上的蜗牛 大大写的扩展系列 http://www.cnblogs.com/cyb331/p/3514555.html   文中的下载连接都失效了,这是扩展1.1的下载连接 http://pan.baidu.com/s/1bngXOAz

如果以前写过sql语句,Dapper用起来算是比较顺手的,基本上还是以前那套 数据库连接,sql语句,记录集 的流程,只不过返回结果的时候就不用去记录集一个字段一个字段的读了了,结果可以直接绑定到模型上....

Dapper项目自带了Contrib 和 Rainbow两个插件,我还没深入去了解,不知道还有没有什么高级功能,暂且当成语法糖吧,随着学习的深入,可能会有更深的理解

从Dapper.net sample 可以看到直接用Dapper和两个插件完成增删改查的区别,如果你也是新手,没接触过,建议把这个范例下回去看看,基本大概就明白了

我这里就简单的把插入数据的代码拿出来,简单做个比较

Dapper直接插入一条数据是这样的

                var supplier = new Supplier()
{
Address = "10 Main Street",
CompanyName = "DEF Corporation"
}; sqlConnection.Execute(
@"
insert Suppliers(CompanyName, Address)
values (@CompanyName, @Address)
",
supplier);

Contrib插件是这样的

                var supplier = new Supplier()
{
Address = "10 Main Street",
CompanyName = "ABC Corporation"
}; var supplierId = sqlConnection.Insert<Supplier>(supplier);

Rainbow是这样的

                int? supplierId = db.Suppliers.Insert(new
{
CompanyName = Guid.NewGuid().ToString() });

感觉上Rainbow在用的时候跟EF的流程差不多,定义Database的时候要把表名和实体(模型)都定义好...感觉这样用就不如直接去用EF了....所以,我的代码里面大都用了Contrib来做

    public class NorthwindDatabase : Database<NorthwindDatabase>
{
public Table<Supplier> Suppliers { get; set; }
}

另外还要介绍就是 树上的蜗牛 写的扩展,看了一下介绍和扩展的内容,感觉以后有些地方可能会用的上,于是也都导入到解决方案里面了...

这里要说明一下的是,蜗牛大大写的DapperEx是从DbBase扩展的,而Contrib是从DbConnecttion扩展的....

为了优化性能,实现一个请求使用一个数据库连接,所以我写了一个DBFactory,用CallContext来存储数据库连接实例,有关CallContext的说明,请msdn或者google,做为初学者,暂时只知道这样做可以就行了...

代码如下

    public static class DBFactory
{ /// <summary>
/// 获取主数据库连接
/// </summary>
/// <returns></returns>
public static DbBase GetSDDB()
{
DbBase db = CallContext.GetData("SDDB") as DbBase;
if (db == null)
{
db = new DbBase("SdConnection");
CallContext.SetData("SDDB", db);
}
return db;
} }

需要数据库的时候这样写就可以了

    public class ServiceBase
{
protected DbBase DB;
public ServiceBase()
{
//取数据库对象
DB = DBFactory.GetSDDB();
}
}

具体操作的时候这样就OK了

        public IEnumerable<StaffUser> GetUserAll(int page = , int rows = )
{
IEnumerable<StaffUser> m = DB.DbConnecttion.Query<StaffUser>(@"
Select *
From StaffUser
order by IsEnable Desc,ID" + SDUtility.GetPageSql(page, rows));
return m;
}

Contrib插件有一个地方很别扭,就是在增删改查的时候,会把Model后面加个s当作表名,这个行为也是学EF,不过人家EF更智能的一点是,会自动把英文单词转换为正确的复数形式,而Contrib就是简单粗暴的在后面加了个s,让我感觉很是不爽,于是乎就粗暴的打开源代码,找到 GetTableName 函数,改之......这样我model什么名字跟数据库的表名相同就OK了....

当时打算用蜗牛大大写的DapperEx,还有一个原因就是原生的dapper不提供翻页支持....这个也让人很是恼火,以前用mssql的时候最恼火的也是这个....不如用mysql,直接limit xx,yy 就行了....

不过后来偶然查资料得知,mssql2012的ORDER BY 语句支持用 offset_fetch 来实现翻页(控制返回的行数) ,微软的msdn里有代码示例 http://msdn.microsoft.com/zh-cn/library/ms188385(v=sql.110).aspx#Offset

所以 SDUtility.GetPageSql 里的代码就简单的许多,直接拼接出 offset_fetch 语句即可

        public static string GetPageSql(int page = , int rows = )
{
page = page - ;
if (page < ) page = ;
if (rows < ) rows = ;
if (page== && rows==)
return ""; return string.Format(" OFFSET {0} ROWS FETCH NEXT {1} ROWS ONLY",page*rows,rows);
}

有了dapper,Contrib还有offset_fetch,再加上高大上sql语句,哦,对了,还有功不可没的Json.net,平时大部分的需求都可以满足了.....

复杂的表关系查询直接一句sql搞定,再也不像EF那样绞尽脑汁的去设计实体了....而且用dynimic和Json.net返回数据,也可以省下很多model,想想还真是有点小鸡冻,吼吼~~~

再就是还有一个可能在实际使用中可能遇到的问题...就是更新和查询的时候,我们有可能只需要model的其中几个属性(字段),我是这样解决的....

在model里面加了个方法,根据不同的操作需要,返回需要的字段,比如,在更新用户信息的时候,,有些字段是不能动的特别用来加密密码的salt字段,一旦生成了就不能动了...

所以我的model会这样写,由于刚接触C#,完全面向对象的思想还没有深入,我也不知道这种写法会不会违反什么编程原则,总之,先凑合能用就行....如果你有更好的方法,也欢迎交流学习......

GetUpdatePart用户返回编辑用户时需要更新的字段(登录次数,最后登录时间,还有salt字段要避开)
PrepareToUpdate 是在更新数据之前调用一下,传回原来数据库中的数据做对比,看看密码是否更改了,如果密码改了,就根据salt重新加密一下
PrepareToInsert 是在插入新数据之前调用,先生成一个salt,然后再对密码进行加密,同时把登录次数,最后登录时间赋值一下,防止出现null
    public class StaffUser
{
[Key] //For Contrib
[Id(CheckAutoId = true)]//for Ex
public int ID { get; set; }
public string UserCode { get; set; }
public string UserName { get; set; }
public string Nick { get; set; }
public string Password { get; set; }
public byte IsEnable {get; set; }
public int LoginCount { get; set; }
public DateTime LastLogin { get; set; }
public string Description { get; set; }
public string salt { get; set; } //只更新部分字段
public string[] GetUpdatePart()
{
return new string[] { "UserCode", "UserName", "Nick", "Password", "IsEnable", "Description" };
}
//更新前准备
public string PrepareToUpdate(StaffUser Old)
{
//检查密码是否被修改
if (Old.Password!=this.Password)
{
//重新生成密码
this.Password = SDUtility.MD5(SDUtility.MD5(this.Password) + Old.salt);
}
return "";
} //添加前准备
public string PrepareToInsert()
{
//生成盐和密码
this.salt = SDUtility.GetSalt();
this.Password = SDUtility.MD5(SDUtility.MD5(this.Password) + this.salt);
LoginCount = ;
LastLogin = DateTime.Now;
return "";
} }

这样,我在插入新数据的时候就可以用 Contrib 了

        private string DoUserInsert(StaffUser row)
{
try
{
//为插入做准备
row.PrepareToInsert();
DB.DbConnecttion.Insert<StaffUser>(row);
return "";
}
catch (Exception ex)
{
return row.ID + row.UserName + "插入失败! " + ex.Message;
}
}

为了用Contrib在update的时候实现只更新部分字段,所以继续对 SqlMapperExtensions 进行改造,增加了一个 UpdatePart 方法,就是把原来的Update方法里更新所有字段改成只更新参数传入的字段

   public static bool UpdatePart<T>(this IDbConnection connection, T entityToUpdate,string[] UpdateProps , IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
var proxy = entityToUpdate as IProxy;
if (proxy != null)
{
if (!proxy.IsDirty) return false;
} var type = typeof(T); var keyProperties = KeyPropertiesCache(type);
if (!keyProperties.Any())
throw new ArgumentException("Entity must have at least one [Key] property"); var name = GetTableName(type); var sb = new StringBuilder();
sb.AppendFormat("update {0} set ", name); var allProperties = TypePropertiesCache(type);
var computedProperties = ComputedPropertiesCache(type);
//var nonIdProps = allProperties.Except(keyProperties.Union(computedProperties)); //只更新指定字段
for (var i = ; i < UpdateProps.Length; i++)
{
var property = UpdateProps[i];
sb.AppendFormat("{0} = @{1}", property, property);
if (i < UpdateProps.Length - )
sb.AppendFormat(", ");
}
sb.Append(" where ");
for (var i = ; i < keyProperties.Count(); i++)
{
var property = keyProperties.ElementAt(i);
sb.AppendFormat("{0} = @{1}", property.Name, property.Name);
if (i < keyProperties.Count() - )
sb.AppendFormat(" and ");
}
var updated = connection.Execute(sb.ToString(), entityToUpdate, commandTimeout: commandTimeout, transaction: transaction);
return updated > ;
}

然后更新数据的时候这样使用...

private string DoUserUpdate(StaffUser row)
{
try
{
//取出原来数据
var old = DB.DbConnecttion.Get<StaffUser>(row.ID);
//为更新做准备
row.PrepareToUpdate(old);
//只更新部分字段
DB.DbConnecttion.UpdatePart<StaffUser>(row,row.GetUpdatePart());
return "";
}
catch (Exception ex)
{
return row.ID + row.UserName + "更新失败! " + ex.Message;
} }

初学C#和MVC的一些心得,弯路,总结,还有教训(3)--Dapper的更多相关文章

  1. 初学C#和MVC的一些心得,弯路,总结,还有教训(2)--关于Entity Framework

    看了一堆视频教程后,感觉基本了解的差不多了,可以动手.....因为最好的学习方法就是实践嘛.... 所以打算从网站做起,在WebForm和MVC之间选了MVC,因为感觉高大上...也比较灵活 于是买了 ...

  2. 初学C#和MVC的一些心得,弯路,总结,还有教训(4)--Cache 关于创建多个缓存实例

    asp.net中的数据缓存可以用 HttpRuntime.Cache ,这个是大家都知道的,但如果缓存的数据比较多,又比较杂乱,想要把缓存分开管理(也就是创建多个缓存实例)应该怎么做呢... 于是常规 ...

  3. 初学C#和MVC的一些心得,弯路,总结,还有教训(1)--语言的选择

    因为惰性,自制力,求知欲等各方面原因....一直没有学新技术,总感觉VB6凑合能用就凑合用.... 于是大概从05年开始,几乎每次新版的vs一发布,我就下载回来,然后安装,然后,,,,就扔那了.... ...

  4. 初学tornado之MVC版helloworld

    作者:the5fire | 标签: MVC  tornado  | 发布:2012-08-06 2:41 p.m. 文接上篇,看我一个简单的helloworld,虽然觉得这个框架着实精小,但是实际开发 ...

  5. ASP.NET MVC 開發心得分享 (21):Routing 觀念與技巧

    ASP.NET MVC 預設在 Global.asax 所定義的 RegisterRoutes 方法中可以輕易的定義你希望擁有的網址格式,嚴格上來講這並非 ASP.NET MVC 的專利,而是從 AS ...

  6. ASP.NET MVC TempData使用心得

    说明: 在ASP.NET MVC中資料傳遞主要有ViewData與TempData ViewData主要是Controller傳遞Data給View,存留期只有一個Action,要跨Action要使用 ...

  7. 初学SpringMVC,使用MVC进行文件上传

    最近在做一个文件上传的功能,走了不少弯路,话不多说,直接上代码: 导入各种jar包,首先是applicationContext.xml配置文件中: <!-- 配置文件解析器 --> < ...

  8. ASP.NET MVC学习系列(一)-WebAPI初探

    由于即将要接手的新项目计划用ASP.NET MVC3来开发,所以最近一段时间一直在看相关的书或文章.因为之前在大学里也曾学习过MVC2开发,也做过几个简单的MVC2的小型测试项目,不过在后来工作以后主 ...

  9. ASP.NET MVC 下拉列表使用小结

    ASP.NET MVC中下拉列表的用法很简单,也很方便,具体来说,主要是页面上支持两种Html帮助类的方法:DropDownList()和DropDownListFor().这篇博文主要作为个人的一个 ...

随机推荐

  1. 线程.FTP.SFTP.打包

    Windows就是多线程模式.每一个解决方案就是一个进程.一个进程下拥有多个线程. 简单点.单核的处理器不存在多线程.是CPU在每一个线程上切换处理.在人反应不过来的情况下完成同步的效果. 比如左手画 ...

  2. [deviceone开发]-do_SegmentView和do_SlideView联动的示例

    一.简介 示例展示do_SegmentView和do_SlideView联动的使用,这二个组件很常用,而且这个组合也非常常用,类似网易新闻的效果,上面滑动带动下面的slideview滑动,反过来也是. ...

  3. FusionCharts的使用方法(超详细)

    今天统计价格变化规律的时候找到的一个很好的文档,很详细 一.简介 Ø FusionCharts 是InfoSoft Global 公司的一个产品,InfoSoft Global 公司是专业的Flash ...

  4. Activity详解二 activity数据传递

    首先看效果图: 1.Bundle类的作用 Bundle类用作携带数据,它类似于Map,用于存放key-value名值对形式的值.相对于Map,它提供了各种常用类型的putXxx()/getXxx()方 ...

  5. iOS 开发之路(WKWebView内嵌HTML5之图片上传) 五

    HTML5页面的图片上传功能在iOS端的实现. 首先,页面上用的是plupload组件,在wkwebview上存在两个坑需要修复才能正常使用. 问题:在webview上点击选择照片/相机拍摄,就会出现 ...

  6. iOS开发之功能模块--根据需求开发横向的子弹盒View

    这个需求是本人工作开发中后期需求要添加的新功能,本人模仿UITableView的代理和数据源方法进行了第一阶段的开发.第二阶段是添加丰富的动画. 这个功能需求描述:能上传添加五个待选头像,五个头像分别 ...

  7. 微信小程序 - 开发指南

    一.下载并安装开发工具 下载地址 二.创建项目 打开开发工具 添加项目 进入预览和调试界面 代码编辑器 编译并预览 三.启动流程 四.适用场景 五.技术框架 六.科普 [图片较大 - 点击查看]

  8. Could not obtain information about Windows NT group/user 'xxxx\xxxx', error code 0x5

    案例描述 昨晚踢球回来,接到电话说一个系统的几个比较重要作业出错,导致系统数据有些问题.让我赶紧检查看看.检查作业日志时发现,作业报如下错误(关键信息用xxx替换) The job failed.  ...

  9. JVM之方法区

     基本特性: 线程共享区域,存储被JVM加载的类信息.常量.静态变量.即时编译器编译的代码等 堆的逻辑部分,不限定方法去内的内存位置和编译代码的管理策略,不限定实现垃圾回收 容量可不定也可动态扩展,不 ...

  10. 【SQL篇章--DATABASE/EVENTS】

    [SQL篇章][SQL语句梳理 :--基于MySQL5.6][已梳理:DATABASE/EVENTS][会坚持完善]   目录: 1. Data Definition Statements: 1.1 ...