相信经常做一些MS,CRM 项目的童鞋非常有体会,大部分时间都是在复制和粘贴,大部分项目框架都是建一个三层,首先是DAL建一些增删改查,然后呢是BLL业务层再建一些增删改查,然后UI层再调用增删改查,整个过程非常的繁琐,开发效率并不是很高,这种项目做久了之后,就非常的痛苦,非常的无聊。今天我给大家带来一个抽象出增删改查的框架,相信有些大牛早就总结出来了,不喜勿喷哈,本人旨在分享。

  你再也不用写增删改查了,我给你抽象出来了!!

  现在业界火了一种ORM 框架,那就是Dapper,我也是Dapper的粉丝之一,而我总结出来的框架也是基于Daaper。下面是我的代码,首先是Dapper Helper类,数据库通用访问类(用Nuget工具先把Dapper类引用到NetUtility.Dapper.Core项目中去):

NetUtility.Dapper.Core.DataBaseAccess.cs  

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dapper;
using System.Data;
using NetUtility.Entity;
using System.Reflection; namespace NetUtility.Dapper.Core
{
/// <summary>
/// 数据库访问类
/// </summary>
public class DataBaseAccess
{
public static SqlConnection CreateConnection()
{
string connStr = ConfigurationManager.ConnectionStrings["connString"].ConnectionString;
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
return conn;
} /// <summary>
/// 执行增、删、改方法
/// </summary>
/// <param name="sql"></param>
/// <param name="parms"></param>
/// <returns></returns>
public static int Execute(string sql, object parms = null)
{
using (IDbConnection conn = CreateConnection())
{
return conn.Execute(sql,parms);
}
} /// <summary>
/// 得到单行单列
/// </summary>
/// <param name="sql"></param>
/// <param name="parms"></param>
/// <returns></returns>
public static object ExecuteScalar(string sql, object parms = null)
{
using (IDbConnection conn = CreateConnection())
{
return conn.ExecuteScalar(sql, parms);
}
} /// <summary>
/// 单个数据集查询
/// </summary>
/// <param name="sql"></param>
/// <param name="parms"></param>
/// <returns></returns>
public static List<TEntity> Query<TEntity>(string sql,Func<TEntity,bool> pre ,object parms = null)
{
using (IDbConnection conn = CreateConnection())
{
return conn.Query<TEntity>(sql, parms).Where(pre).ToList();
}
} /// <summary>
/// 单个数据集查询
/// </summary>
/// <param name="sql"></param>
/// <param name="parms"></param>
/// <returns></returns>
public static List<TEntity> Query<TEntity>(string sql, object parms = null)
{
using (IDbConnection conn = CreateConnection())
{
return conn.Query<TEntity>(sql, parms).ToList();
}
} /// <summary>
/// 多个数据集查询
/// </summary>
/// <param name="sql"></param>
/// <param name="parms"></param>
/// <returns></returns>
public static SqlMapper.GridReader MultyQuery(string sql, object parms = null)
{
using (IDbConnection conn = CreateConnection())
{
return conn.QueryMultiple(sql, parms);
}
} /// <summary>
/// 单个数据集查询
/// </summary>
/// <param name="sql"></param>
/// <param name="parms"></param>
/// <returns></returns>
public static TEntity FirstOrDefault<TEntity>(string sql,Func<TEntity,bool> selector, object parms = null)
{
using (IDbConnection conn = CreateConnection())
{
return conn.Query<TEntity>(sql, parms).Where(selector).FirstOrDefault();
}
}
}
}

我把增删改查抽象出来了,少不了的就是SQL语句的生成,生成SQL语句,要么是映射,要么是反射,而我用的是反射,给一个Entity类,我读取他所有属性和字段,然后生成对应的SQL语句。

NetUtility.Dapper.Core.DataMapping.cs

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks; namespace NetUtility.Dapper.Core
{
internal class DataMapping<TModel> where TModel : class
{
#region 数据库类型+DataBaseType
/// <summary>
/// 数据库类型
/// </summary>
public static string DataBaseType
{
get
{
string strType = ConfigurationManager.AppSettings["DataBaseType"];
if (!string.IsNullOrEmpty(strType))
{
return strType;
}
else
{
return string.Empty;
}
}
}
#endregion #region 主键属性字段+PrimaryKey
/// <summary>
/// 主键字段名称
/// </summary>
public static string PrimaryKey
{
get
{
Type t = typeof(TModel);
TableInfoAttribute tableInfo = t.GetCustomAttribute(typeof(TableInfoAttribute), true) as TableInfoAttribute;
if (tableInfo!=null)//如果没有标识表信息特性,则通过表名向数据库中得到主键信息
{
return tableInfo.PrimaryKey;
}
else
{
string tableName = TableName();
return DataBaseAccess.ExecuteScalar("SELECT name FROM SysColumns WHERE id=Object_Id('" + tableName + "') and colid=(select top 1 colid from sysindexkeys where id=Object_Id('" + tableName + "'))").ToString();
}
}
}
#endregion #region 获取表名+TableName
/// <summary>
/// 获取表名
/// </summary>
/// <param name="prev">数据库表名前缀</param>
/// <returns></returns>
public static string TableName(string prev = "")
{
Type t = typeof(TModel);
TableInfoAttribute tableInfo = t.GetCustomAttribute(typeof(TableInfoAttribute), true) as TableInfoAttribute;
return tableInfo != null ? tableInfo.TableName : string.Concat(prev, t.Name);
}
#endregion #region Select 查询语句+GetQuerySql
/// <summary>
/// Select 查询语句
/// </summary>
/// <returns></returns>
public static string GetQuerySql()
{
StringBuilder sql = new StringBuilder("select * from ");
sql.Append(TableName()); return sql.ToString();
}
#endregion #region Insert非Null属性的对象实例 Sql 语句+GetInsertSql
/// <summary>
/// Insert 非Null属性的对象实例 Sql 语句
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public static string GetInsertSql(TModel model)
{
StringBuilder sql = new StringBuilder("insert into "); string[] props = Propertys(model);
sql.Append(TableName());
sql.Append("(");
sql.Append(string.Join(",", props));
sql.Append(") values(@");
sql.Append(string.Join(",@", props));
sql.Append(");select @@IDENTITY"); return sql.ToString();
}
#endregion #region Delete Sql 语句+GetDeleteSql
/// <summary>
/// Delete Sql 语句
/// </summary>
/// <returns></returns>
public static string GetDeleteSql()
{
return string.Format(@"delete from {0} where {1} in @IdList", TableName(), PrimaryKey);
}
#endregion #region Update 非Null属性的对象实例 Sql语句+GetUpdateSql
/// <summary>
/// Update 非Null属性的对象实例 Sql语句
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public static string GetUpdateSql(TModel model)
{
StringBuilder sql = new StringBuilder("update ");
string[] props = Propertys(model);
sql.Append(TableName());
sql.Append(" set ");
foreach (string propName in props)
{
sql.Append(propName + "=@" + propName + ",");
}
sql.Remove(sql.Length - , );
sql.Append(" where " + PrimaryKey + "=@Id");
return sql.ToString();
}
#endregion #region 非主键且非Null属性集合+Propertys
/// <summary>
/// 非主键且非Null属性
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public static string[] Propertys(TModel model)
{
PropertyInfo[] props = typeof(TModel).GetProperties();
List<string> list = new List<string>();
string key = PrimaryKey;
if (props != null && props.Length > )
{
foreach (PropertyInfo prop in props)
{
if (prop.GetValue(model, null) != null && !prop.Name.Equals(key, StringComparison.OrdinalIgnoreCase))
{
list.Add(prop.Name);
}
}
} return list.ToArray();
}
#endregion
}
}

代码中的TableInfoAttribute 类是我建一个属性特性类,用于标识表名和主键名称的特性类,假如Entity实体类上面没有标识主键名称,框架默认会用Entity类名作为表名,建议最好标识一下表名和主键名称。

NetUtility.Dapper.Core.TableInfoAttribute.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace NetUtility.Dapper.Core
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
/// <summary>
/// 标识表名、主键等信息特性类
/// </summary>
public class TableInfoAttribute : Attribute
{
/// <summary>
/// 数据库表名
/// </summary>
public string TableName { get; set; } /// <summary>
/// 主键名称
/// </summary>
public string PrimaryKey { get; set; } public TableInfoAttribute()
{ }
public TableInfoAttribute(string tableName, string key)
{
this.TableName = tableName;
this.PrimaryKey = key;
}
}
}

好,下面就是新建一个抽象类,用于抽象出增删改查的 ExecuteSql<TModel> 泛型抽象类

 NetUtility.Dapper.Core.ExecuteSql.cs

using Dapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace NetUtility.Dapper.Core
{
public abstract class ExecuteSql<TModel> where TModel : class
{
#region Insert非Null属性的对象实例+Insert(TModel model)
/// <summary>
/// Insert非Null属性的对象实例
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public virtual int Insert(TModel model)
{
string sql = DataMapping<TModel>.GetInsertSql(model);
object res = DataBaseAccess.ExecuteScalar(sql, model);
if (res != null)
{
return Convert.ToInt32(res);
}
return ;
}
#endregion #region Select * 查询+Query()
/// <summary>
/// Select * 查询
/// </summary>
/// <returns></returns>
public virtual List<TModel> Query()
{
string sql = DataMapping<TModel>.GetQuerySql();
return DataBaseAccess.Query<TModel>(sql);
}
#endregion #region 带查询条件的Select查询+Query(Func<TModel, bool> selector)
/// <summary>
/// 带查询条件的Select查询
/// </summary>
/// <param name="selector"></param>
/// <returns></returns>
public virtual List<TModel> Query(Func<TModel, bool> selector)
{
string sql = DataMapping<TModel>.GetQuerySql();
return DataBaseAccess.Query<TModel>(sql, selector);
}
#endregion #region 得到一个对象的实例+FirstOrDefault(Func<TModel, bool> selector = null)
/// <summary>
/// 得到一个对象的实例
/// </summary>
/// <param name="selector"></param>
/// <returns></returns>
public virtual TModel FirstOrDefault(Func<TModel, bool> selector = null)
{
string sql = DataMapping<TModel>.GetQuerySql();
return DataBaseAccess.FirstOrDefault<TModel>(sql, selector);
}
#endregion #region 批量删除+Delete(string[] IdList)
/// <summary>
/// 批量删除
/// </summary>
/// <param name="IdList"></param>
/// <returns></returns>
public virtual int Delete(string[] IdList)
{
return DataBaseAccess.Execute(DataMapping<TModel>.GetDeleteSql(), new { IdList = IdList });
}
#endregion #region Update 一个非Null属性的对象+Update(TModel model)
/// <summary>
/// Update 一个非Null属性的对象
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public virtual int Update(TModel model)
{
return DataBaseAccess.Execute(DataMapping<TModel>.GetUpdateSql(model), model);
}
#endregion #region 获取多个数据集+MultyQuery(string sql, object param = null)
/// <summary>
/// 获取多个数据集
/// </summary>
/// <param name="sql"></param>
/// <param name="param"></param>
/// <returns></returns>
public virtual SqlMapper.GridReader MultyQuery(string sql, object param = null)
{
return DataBaseAccess.MultyQuery(sql, param);
}
#endregion }
}

ExecuteSql.cs 类中的方法全是 virsual方法,使用者可以重写他,特别是查询方法,一定会被重写掉。现在NetUtility.Dapper.Core项目中的类全部写完了,现在是我业务类的引用了,我现在只需要建一个业务类继承这个抽象类,这些增删改查方法全都有了,已经不需要写了!

下面是我的两个实体类,实体类用TableInfoAttribute特性类标识出了主键名称和表名称:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NetUtility.Dapper.Core; namespace NetUtility.Entity
{
[TableInfo(PrimaryKey ="Id",TableName ="Classes")]
public class Classes
{ public int Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
}
} using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NetUtility.Dapper.Core; namespace NetUtility.Entity
{
[TableInfo(PrimaryKey = "Id", TableName = "Student")]
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public int? Age { get; set; }
public DateTime? JoinDate { get; set; }
public int? ClassesId { get; set; }
}
}

我再新建一个StudentRepertories业务类,继承ExecuteSql抽象类。

NetUtility.Repertories.StudentRepertories.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NetUtility.Dapper.Core;
using NetUtility.Entity;
using NetUtility.Entity.ExstendEntity;//这个是实体类的扩展类,项目中如不需要可移除
using System.Data;
using Dapper; namespace NetUtility.Repertories
{
public class StudentRepertories : ExecuteSql<Student>
{ public override List<Student> Query()
{
return base.Query();
} public List<StudentInfo> QueryInfo()
{
string sql = "select * from Student a left join Classes b on a.ClassesId=b.Id"; using (IDbConnection conn = DataBaseAccess.CreateConnection())
{
return conn.Query<StudentInfo, Classes, StudentInfo>(sql, (stu, classes) => { stu.ClassesModel = classes; return stu; }).ToList();
}
}
}
}

好了,现在我们只需要建一个控制台测试一下有没有问题就是了,亲测,木有问题。

NetUtility.ConsoleItem

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NetUtility.Repertories;
using NetUtility.Entity; namespace NetUtility.ConsoleItem
{
class Program
{
static void Main(string[] args)
{
//业务对象
StudentRepertories stu = new StudentRepertories();
//实体对象
var model = new Student(){Age = ,ClassesId = ,Code = "",JoinDate = DateTime.Now,Name = "老徐"};
//新增一个对象
int StudentId = stu.Insert(model);
var newModel = stu.FirstOrDefault(a => a.Id == StudentId);
//Lambda表达式查询
var list = stu.Query(a => a.Age == );
//不带参数查询
var studentInfoList = stu.QueryInfo();
#region 更新
newModel.Code = "";
newModel.Id = StudentId;
stu.Update(newModel);
#endregion
// 删除
stu.Delete(new string[] { newModel.Id.ToString() });
Console.ReadKey();
}
}
}

各位可以指出我上面的程序一些毛病,相互交流一下,或者有什么更新的做法也可以说说

  

让C#开发更简单,抽象增删改的更多相关文章

  1. MyBatis学习--简单的增删改查

    jdbc程序 在学习MyBatis的时候先简单了解下JDBC编程的方式,我们以一个简单的查询为例,使用JDBC编程,如下: Public static void main(String[] args) ...

  2. salesforce 零基础学习(五十一)使用 Salesforce.com SOAP API 实现用户登录以及简单的增删改查(JAVA访问salesforce)

    此篇请参看:https://resources.docs.salesforce.com/202/latest/en-us/sfdc/pdf/salesforce_developer_environme ...

  3. 通过JDBC进行简单的增删改查

    通过JDBC进行简单的增删改查(以MySQL为例) 目录 前言:什么是JDBC 一.准备工作(一):MySQL安装配置和基础学习 二.准备工作(二):下载数据库对应的jar包并导入 三.JDBC基本操 ...

  4. MVC3.0+knockout.js+Ajax 实现简单的增删改查

    MVC3.0+knockout.js+Ajax 实现简单的增删改查 自从到北京入职以来就再也没有接触MVC,很多都已经淡忘了,最近一直在看knockout.js 和webAPI,本来打算采用MVC+k ...

  5. SpringMVC之简单的增删改查示例(SSM整合)

    本篇文章主要介绍了SpringMVC之简单的增删改查示例(SSM整合),这个例子是基于SpringMVC+Spring+Mybatis实现的.有兴趣的可以了解一下. 虽然已经在做关于SpringMVC ...

  6. 通过JDBC进行简单的增删改查(以MySQL为例) 目录

    通过JDBC进行简单的增删改查(以MySQL为例) 目录 前言:什么是JDBC 一.准备工作(一):MySQL安装配置和基础学习 二.准备工作(二):下载数据库对应的jar包并导入 三.JDBC基本操 ...

  7. Java通过JDBC进行简单的增删改查(以MySQL为例)

    Java通过JDBC进行简单的增删改查(以MySQL为例) 目录: 前言:什么是JDBC 一.准备工作(一):MySQL安装配置和基础学习 二.准备工作(二):下载数据库对应的jar包并导入 三.JD ...

  8. 使用 NodeJS+Express+MySQL 实现简单的增删改查

    关于node.js暂时记录如下,以后有时间一定学习 文章来自简书,作者:sprint,2016-07 使用 Node.js + Express+MySQL 实现简单的增删改查 https://www. ...

  9. 用CI框架向数据库中实现简单的增删改查

    以下代码基于CodeIgniter_2.1.3版 用PHP向数据库中实现简单的增删改查(纯代码)请戳 http://www.cnblogs.com/corvoh/p/4641476.html Code ...

随机推荐

  1. Gradle深入与实战(转)

    转自:NO END FOR LEARNINGhttp://benweizhu.github.io/blog/2015/01/31/deep-into-gradle-in-action-1/ 什么是构建 ...

  2. [原]openstack-kilo--issue(五) neutron-agent服务实际是active的-但是显示为XXX

    问题出现: 重启后出现了这样的情况: 查看详细的参数 查看数据库neutron 中对应的agents表.发现表中没有alive这个字段 这些服务的实际状态为active: ----1------● n ...

  3. 烂泥:LVM学习之逻辑卷及卷组缩小空间

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 上一篇文章,我们学习了如何给LVM的逻辑卷及卷组扩容.这篇文章我们来学习,如何给LVM的逻辑卷及卷组缩小空间. 注意逻辑卷的缩小一定要离线操作,不能是在 ...

  4. 简单谈谈RAID

    RAID是“Redundant Array of Independent Disk”的缩写,翻译过来叫做独立磁盘的冗余阵列,其实就是磁盘的存储.访问.备份技术.在谈RAID之前,先简单学习一下存储器的 ...

  5. VMware 12Pro 安装MACOS 10.10

    前言 最近帮人MacBook PRO重新安装了下10.10,在加上用了IP6,对苹果系统很有好感,所以想自己装个mac系统玩一下.虽然有了surface pro3 但是看了时间久了厌了,好想买个MAC ...

  6. 去哪儿网2017校招在线笔试(前端工程师)编程题及JavaScript代码

    编程题很简单.整个试卷结构为: 一.问答题: 对前端的理解,了解哪些框架库? 二.在线编程题:身份证分组 如下第一道:身份证分组 三.在线编程题:身份证分组.统计字符.酒店价格(三选二) 如下第二三四 ...

  7. CORDIC原理与FPGA实现(1)

    CORDIC算法的来历与用途大家网上随处可以见到,这里写 一下自己的理解. 将P(x,y)旋转角度a得到新的坐标P’(x’,y’).这里的坐标变换为: x’= x cos(a) – y sin(a)  ...

  8. hdu-5495 LCS(置换)

    题目链接: LCS Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...

  9. codeforces 710E E. Generate a String(dp)

    题目链接: E. Generate a String time limit per test 2 seconds memory limit per test 512 megabytes input s ...

  10. HDU 5025 Saving Tang Monk --BFS

    题意:给一个地图,孙悟空(K)救唐僧(T),地图中'S'表示蛇,第一次到这要杀死蛇(蛇最多5条),多花费一分钟,'1'~'m'表示m个钥匙(m<=9),孙悟空要依次拿到这m个钥匙,然后才能去救唐 ...