让C#开发更简单,抽象增删改

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

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

[[134553]]

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

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

NetUtility.Dapper.Core.DataBaseAccess.cs  

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Configuration; 
  4. using System.Data.SqlClient; 
  5. using System.Linq; 
  6. using System.Text; 
  7. using System.Threading.Tasks; 
  8. using Dapper; 
  9. using System.Data; 
  10. using NetUtility.Entity; 
  11. using System.Reflection; 
  12.  
  13. namespace NetUtility.Dapper.Core 
  14.     /// <summary> 
  15.     /// 数据库访问类 
  16.     /// </summary> 
  17.     public class DataBaseAccess 
  18.     { 
  19.         public static SqlConnection CreateConnection() 
  20.         { 
  21.             string connStr = ConfigurationManager.ConnectionStrings["connString"].ConnectionString; 
  22.             SqlConnection conn = new SqlConnection(connStr); 
  23.             conn.Open(); 
  24.             return conn; 
  25.         } 
  26.  
  27.         /// <summary> 
  28.         /// 执行增、删、改方法 
  29.         /// </summary> 
  30.         /// <param name="sql"></param> 
  31.         /// <param name="parms"></param> 
  32.         /// <returns></returns> 
  33.         public static int Execute(string sql, object parms = null) 
  34.         { 
  35.             using (IDbConnection conn = CreateConnection()) 
  36.             { 
  37.                 return conn.Execute(sql,parms); 
  38.             } 
  39.         } 
  40.  
  41.         /// <summary> 
  42.         /// 得到单行单列 
  43.         /// </summary> 
  44.         /// <param name="sql"></param> 
  45.         /// <param name="parms"></param> 
  46.         /// <returns></returns> 
  47.         public static object ExecuteScalar(string sql, object parms = null) 
  48.         { 
  49.             using (IDbConnection conn = CreateConnection()) 
  50.             { 
  51.                 return conn.ExecuteScalar(sql, parms); 
  52.             } 
  53.         } 
  54.  
  55.         /// <summary> 
  56.         /// 单个数据集查询 
  57.         /// </summary> 
  58.         /// <param name="sql"></param> 
  59.         /// <param name="parms"></param> 
  60.         /// <returns></returns> 
  61.         public static List<TEntity> Query<TEntity>(string sql,Func<TEntity,bool> pre ,object parms = null) 
  62.         { 
  63.             using (IDbConnection conn = CreateConnection()) 
  64.             { 
  65.                 return conn.Query<TEntity>(sql, parms).Where(pre).ToList(); 
  66.             } 
  67.         } 
  68.  
  69.         /// <summary> 
  70.         /// 单个数据集查询 
  71.         /// </summary> 
  72.         /// <param name="sql"></param> 
  73.         /// <param name="parms"></param> 
  74.         /// <returns></returns> 
  75.         public static List<TEntity> Query<TEntity>(string sql, object parms = null) 
  76.         { 
  77.             using (IDbConnection conn = CreateConnection()) 
  78.             { 
  79.                 return conn.Query<TEntity>(sql, parms).ToList(); 
  80.             } 
  81.         }    
  82.  
  83.         /// <summary> 
  84.         /// 多个数据集查询 
  85.         /// </summary> 
  86.         /// <param name="sql"></param> 
  87.         /// <param name="parms"></param> 
  88.         /// <returns></returns> 
  89.         public static SqlMapper.GridReader MultyQuery(string sql, object parms = null) 
  90.         { 
  91.             using (IDbConnection conn = CreateConnection()) 
  92.             { 
  93.                 return  conn.QueryMultiple(sql, parms); 
  94.             } 
  95.         } 
  96.  
  97.         /// <summary> 
  98.         /// 单个数据集查询 
  99.         /// </summary> 
  100.         /// <param name="sql"></param> 
  101.         /// <param name="parms"></param> 
  102.         /// <returns></returns> 
  103.         public static TEntity FirstOrDefault<TEntity>(string sql,Func<TEntity,bool> selector, object parms = null) 
  104.         { 
  105.             using (IDbConnection conn = CreateConnection()) 
  106.             { 
  107.                 return conn.Query<TEntity>(sql, parms).Where(selector).FirstOrDefault(); 
  108.             } 
  109.         } 
  110.     } 
  111. }

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

 
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Configuration; 
  4. using System.Linq; 
  5. using System.Reflection; 
  6. using System.Text; 
  7. using System.Threading.Tasks; 
  8.  
  9. namespace NetUtility.Dapper.Core 
  10.     internal class DataMapping<TModel> where TModel : class 
  11.     { 
  12.         #region 数据库类型+DataBaseType 
  13.         /// <summary> 
  14.         /// 数据库类型 
  15.         /// </summary> 
  16.         public static string DataBaseType 
  17.         { 
  18.             get 
  19.             { 
  20.                 string strType = ConfigurationManager.AppSettings["DataBaseType"]; 
  21.                 if (!string.IsNullOrEmpty(strType)) 
  22.                 { 
  23.                     return strType; 
  24.                 } 
  25.                 else 
  26.                 { 
  27.                     return string.Empty; 
  28.                 } 
  29.             } 
  30.         }  
  31.         #endregion 
  32.  
  33.         #region 主键属性字段+PrimaryKey 
  34.         /// <summary> 
  35.         /// 主键字段名称 
  36.         /// </summary> 
  37.         public static string PrimaryKey 
  38.         { 
  39.             get 
  40.             { 
  41.                 Type t = typeof(TModel); 
  42.                 TableInfoAttribute tableInfo = t.GetCustomAttribute(typeof(TableInfoAttribute), true) as TableInfoAttribute;    
  43.                 if (tableInfo!=null)//如果没有标识表信息特性,则通过表名向数据库中得到主键信息 
  44.                 { 
  45.                     return tableInfo.PrimaryKey;               
  46.                 } 
  47.                 else 
  48.                 { 
  49.                     string tableName = TableName(); 
  50.                     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(); 
  51.                 } 
  52.             } 
  53.         }  
  54.         #endregion 
  55.  
  56.         #region 获取表名+TableName 
  57.         /// <summary> 
  58.         /// 获取表名 
  59.         /// </summary> 
  60.         /// <param name="prev">数据库表名前缀</param> 
  61.         /// <returns></returns> 
  62.         public static string TableName(string prev = ""
  63.         { 
  64.             Type t = typeof(TModel); 
  65.             TableInfoAttribute tableInfo = t.GetCustomAttribute(typeof(TableInfoAttribute), true) as TableInfoAttribute; 
  66.             return tableInfo != null ? tableInfo.TableName : string.Concat(prev, t.Name); 
  67.         }  
  68.         #endregion 
  69.  
  70.         #region Select 查询语句+GetQuerySql 
  71.         /// <summary> 
  72.         /// Select 查询语句 
  73.         /// </summary> 
  74.         /// <returns></returns> 
  75.         public static string GetQuerySql() 
  76.         { 
  77.             StringBuilder sql = new StringBuilder("select * from "); 
  78.             sql.Append(TableName()); 
  79.  
  80.             return sql.ToString(); 
  81.         }  
  82.         #endregion 
  83.  
  84.         #region Insert非Null属性的对象实例 Sql 语句+GetInsertSql 
  85.         /// <summary> 
  86.         /// Insert 非Null属性的对象实例 Sql 语句 
  87.         /// </summary> 
  88.         /// <param name="model"></param> 
  89.         /// <returns></returns> 
  90.         public static string GetInsertSql(TModel model) 
  91.         { 
  92.             StringBuilder sql = new StringBuilder("insert into "); 
  93.  
  94.             string[] props = Propertys(model); 
  95.             sql.Append(TableName()); 
  96.             sql.Append("("); 
  97.             sql.Append(string.Join(",", props)); 
  98.             sql.Append(") values(@"); 
  99.             sql.Append(string.Join(",@", props)); 
  100.             sql.Append(");select @@IDENTITY"); 
  101.  
  102.             return sql.ToString(); 
  103.         }  
  104.         #endregion 
  105.  
  106.         #region Delete Sql 语句+GetDeleteSql 
  107.         /// <summary> 
  108.         /// Delete Sql 语句 
  109.         /// </summary> 
  110.         /// <returns></returns> 
  111.         public static string GetDeleteSql() 
  112.         { 
  113.             return string.Format(@"delete from {0} where {1} in @IdList", TableName(), PrimaryKey); 
  114.         }  
  115.         #endregion 
  116.  
  117.         #region Update 非Null属性的对象实例 Sql语句+GetUpdateSql 
  118.         /// <summary> 
  119.         /// Update 非Null属性的对象实例 Sql语句 
  120.         /// </summary> 
  121.         /// <param name="model"></param> 
  122.         /// <returns></returns> 
  123.         public static string GetUpdateSql(TModel model) 
  124.         { 
  125.             StringBuilder sql = new StringBuilder("update "); 
  126.             string[] props = Propertys(model); 
  127.             sql.Append(TableName()); 
  128.             sql.Append(" set "); 
  129.             foreach (string propName in props) 
  130.             { 
  131.                 sql.Append(propName + "=@" + propName + ","); 
  132.             } 
  133.             sql.Remove(sql.Length - 1, 1); 
  134.             sql.Append(" where " + PrimaryKey + "=@Id"); 
  135.             return sql.ToString(); 
  136.         }  
  137.         #endregion 
  138.  
  139.         #region 非主键且非Null属性集合+Propertys 
  140.         /// <summary> 
  141.         /// 非主键且非Null属性 
  142.         /// </summary> 
  143.         /// <param name="model"></param> 
  144.         /// <returns></returns> 
  145.         public static string[] Propertys(TModel model) 
  146.         { 
  147.             PropertyInfo[] props = typeof(TModel).GetProperties(); 
  148.             List<string> list = new List<string>(); 
  149.             string key = PrimaryKey; 
  150.             if (props != null && props.Length > 0) 
  151.             { 
  152.                 foreach (PropertyInfo prop in props) 
  153.                 { 
  154.                     if (prop.GetValue(model, null) != null && !prop.Name.Equals(key, StringComparison.OrdinalIgnoreCase)) 
  155.                     { 
  156.                         list.Add(prop.Name); 
  157.                     } 
  158.                 } 
  159.             } 
  160.  
  161.             return list.ToArray(); 
  162.         }  
  163.         #endregion 
  164.     } 
 

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

NetUtility.Dapper.Core.TableInfoAttribute.cs

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Text; 
  5. using System.Threading.Tasks; 
  6.  
  7. namespace NetUtility.Dapper.Core 
  8.     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = true, Inherited = true)] 
  9.     /// <summary> 
  10.     /// 标识表名、主键等信息特性类 
  11.     /// </summary> 
  12.     public class TableInfoAttribute : Attribute 
  13.     { 
  14.         /// <summary> 
  15.         /// 数据库表名 
  16.         /// </summary> 
  17.         public string TableName { get; set; } 
  18.  
  19.         /// <summary> 
  20.         /// 主键名称 
  21.         /// </summary> 
  22.         public string PrimaryKey { get; set; } 
  23.  
  24.         public TableInfoAttribute() 
  25.         { } 
  26.         public TableInfoAttribute(string tableName, string key) 
  27.         { 
  28.             this.TableName = tableName; 
  29.             this.PrimaryKey = key; 
  30.         } 
  31.     } 
  32. }using System; 
  33. using System.Collections.Generic; 
  34. using System.Linq; 
  35. using System.Text; 
  36. using System.Threading.Tasks; 
  37.  
  38. namespace NetUtility.Dapper.Core 
  39.     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = true, Inherited = true)] 
  40.     /// <summary> 
  41.     /// 标识表名、主键等信息特性类 
  42.     /// </summary> 
  43.     public class TableInfoAttribute : Attribute 
  44.     { 
  45.         /// <summary> 
  46.         /// 数据库表名 
  47.         /// </summary> 
  48.         public string TableName { get; set; } 
  49.  
  50.         /// <summary> 
  51.         /// 主键名称 
  52.         /// </summary> 
  53.         public string PrimaryKey { get; set; } 
  54.  
  55.         public TableInfoAttribute() 
  56.         { } 
  57.         public TableInfoAttribute(string tableName, string key) 
  58.         { 
  59.             this.TableName = tableName; 
  60.             this.PrimaryKey = key; 
  61.         } 
  62.     } 

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

NetUtility.Dapper.Core.ExecuteSql.cs

  1. using Dapper; 
  2. using System; 
  3. using System.Collections.Generic; 
  4. using System.Linq; 
  5. using System.Text; 
  6. using System.Threading.Tasks; 
  7.  
  8. namespace NetUtility.Dapper.Core 
  9.     public abstract class ExecuteSql<TModel> where TModel : class 
  10.     { 
  11.         #region Insert非Null属性的对象实例+Insert(TModel model) 
  12.         /// <summary> 
  13.         /// Insert非Null属性的对象实例 
  14.         /// </summary> 
  15.         /// <param name="model"></param> 
  16.         /// <returns></returns> 
  17.         public virtual int Insert(TModel model) 
  18.         { 
  19.             string sql = DataMapping<TModel>.GetInsertSql(model); 
  20.             object res = DataBaseAccess.ExecuteScalar(sql, model); 
  21.             if (res != null
  22.             { 
  23.                 return Convert.ToInt32(res); 
  24.             } 
  25.             return 0; 
  26.         }  
  27.         #endregion 
  28.  
  29.         #region Select * 查询+Query() 
  30.         /// <summary> 
  31.         /// Select * 查询 
  32.         /// </summary>     
  33.         /// <returns></returns> 
  34.         public virtual List<TModel> Query() 
  35.         { 
  36.             string sql = DataMapping<TModel>.GetQuerySql(); 
  37.             return DataBaseAccess.Query<TModel>(sql); 
  38.         }  
  39.         #endregion 
  40.  
  41.         #region 带查询条件的Select查询+Query(Func<TModel, bool> selector) 
  42.         /// <summary> 
  43.         /// 带查询条件的Select查询 
  44.         /// </summary> 
  45.         /// <param name="selector"></param> 
  46.         /// <returns></returns> 
  47.         public virtual List<TModel> Query(Func<TModel, bool> selector) 
  48.         { 
  49.             string sql = DataMapping<TModel>.GetQuerySql(); 
  50.             return DataBaseAccess.Query<TModel>(sql, selector); 
  51.         }  
  52.         #endregion 
  53.  
  54.         #region  得到一个对象的实例+FirstOrDefault(Func<TModel, bool> selector = null) 
  55.         /// <summary> 
  56.         /// 得到一个对象的实例 
  57.         /// </summary> 
  58.         /// <param name="selector"></param> 
  59.         /// <returns></returns> 
  60.         public virtual TModel FirstOrDefault(Func<TModel, bool> selector = null
  61.         { 
  62.             string sql = DataMapping<TModel>.GetQuerySql(); 
  63.             return DataBaseAccess.FirstOrDefault<TModel>(sql, selector); 
  64.         }  
  65.         #endregion 
  66.  
  67.         #region 批量删除+Delete(string[] IdList) 
  68.         /// <summary> 
  69.         /// 批量删除 
  70.         /// </summary> 
  71.         /// <param name="IdList"></param> 
  72.         /// <returns></returns> 
  73.         public virtual int Delete(string[] IdList) 
  74.         { 
  75.             return DataBaseAccess.Execute(DataMapping<TModel>.GetDeleteSql(), new { IdList = IdList }); 
  76.         }  
  77.         #endregion 
  78.  
  79.         #region Update 一个非Null属性的对象+Update(TModel model) 
  80.         /// <summary> 
  81.         /// Update 一个非Null属性的对象 
  82.         /// </summary> 
  83.         /// <param name="model"></param> 
  84.         /// <returns></returns> 
  85.         public virtual int Update(TModel model) 
  86.         { 
  87.             return DataBaseAccess.Execute(DataMapping<TModel>.GetUpdateSql(model), model); 
  88.         }  
  89.         #endregion 
  90.  
  91.         #region 获取多个数据集+MultyQuery(string sql, object param = null) 
  92.         /// <summary> 
  93.         /// 获取多个数据集 
  94.         /// </summary> 
  95.         /// <param name="sql"></param> 
  96.         /// <param name="param"></param> 
  97.         /// <returns></returns> 
  98.         public virtual SqlMapper.GridReader MultyQuery(string sql, object param = null
  99.         { 
  100.             return DataBaseAccess.MultyQuery(sql, param); 
  101.         }  
  102.         #endregion 
  103.  
  104.         
  105.     } 

 

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

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

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Text; 
  5. using System.Threading.Tasks; 
  6. using NetUtility.Dapper.Core; 
  7.  
  8. namespace NetUtility.Entity 
  9.     [TableInfo(PrimaryKey ="Id",TableName ="Classes")] 
  10.     public class Classes 
  11.     {   public int Id { get; set; } 
  12.         public string Name { get; set; } 
  13.         public string Code { get; set; } 
  14.     } 
  15.  
  16. using System; 
  17. using System.Collections.Generic; 
  18. using System.Linq; 
  19. using System.Text; 
  20. using System.Threading.Tasks; 
  21. using NetUtility.Dapper.Core; 
  22.  
  23. namespace NetUtility.Entity 
  24.     [TableInfo(PrimaryKey = "Id", TableName = "Student")] 
  25.     public class Student 
  26.     {        
  27.         public int Id { get; set; } 
  28.         public string Name { get; set; } 
  29.         public string Code { get; set; } 
  30.         public int? Age { get; set; } 
  31.         public DateTime? JoinDate { get; set; } 
  32.         public int? ClassesId { get; set; } 
  33.     } 

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

NetUtility.Repertories.StudentRepertories.cs

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Text; 
  5. using System.Threading.Tasks; 
  6. using NetUtility.Dapper.Core; 
  7. using NetUtility.Entity; 
  8. using NetUtility.Entity.ExstendEntity;//这个是实体类的扩展类,项目中如不需要可移除 
  9. using System.Data; 
  10. using Dapper; 
  11.  
  12. namespace NetUtility.Repertories 
  13.     public class StudentRepertories : ExecuteSql<Student> 
  14.     { 
  15.  
  16.         public override List<Student> Query() 
  17.         { 
  18.             return base.Query(); 
  19.         } 
  20.  
  21.         public  List<StudentInfo> QueryInfo() 
  22.         { 
  23.             string sql = "select * from Student a left join Classes b on a.ClassesId=b.Id"
  24.  
  25.             using (IDbConnection conn = DataBaseAccess.CreateConnection()) 
  26.             { 
  27.                 return conn.Query<StudentInfo, Classes, StudentInfo>(sql, (stu, classes) => { stu.ClassesModel = classes; return stu; }).ToList();    
  28.             } 
  29.         } 
  30.     } 

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

NetUtility.ConsoleItem

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Text; 
  5. using System.Threading.Tasks; 
  6. using NetUtility.Repertories; 
  7. using NetUtility.Entity; 
  8.  
  9. namespace NetUtility.ConsoleItem 
  10.     class Program 
  11.     { 
  12.         static void Main(string[] args) 
  13.         { 
  14.             //业务对象 
  15.              StudentRepertories stu = new StudentRepertories(); 
  16.             //实体对象 
  17.             var model = new Student(){Age = 100,ClassesId = 1,Code = "3200020021",JoinDate = DateTime.Now,Name = "老徐"};        
  18.             //新增一个对象 
  19.             int StudentId = stu.Insert(model); 
  20.             var newModel = stu.FirstOrDefault(a => a.Id == StudentId);  
  21.             //Lambda表达式查询 
  22.             var list = stu.Query(a => a.Age == 100); 
  23.             //不带参数查询 
  24.             var studentInfoList = stu.QueryInfo();  
  25.             #region 更新 
  26.             newModel.Code = "1111111111"
  27.             newModel.Id = StudentId; 
  28.             stu.Update(newModel); 
  29.             #endregion 
  30.           // 删除 
  31.             stu.Delete(new string[] { newModel.Id.ToString() });          
  32.             Console.ReadKey(); 
  33.         } 
  34.     } 

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

责任编辑:王雪燕 来源: 博客园
相关推荐

2009-09-04 13:31:33

C#抽象类

2014-10-15 09:35:26

Android Wea

2009-08-10 10:04:25

C#抽象类C#接口

2009-05-15 17:42:34

ApacheWeb开发Apache Slin

2012-06-20 13:36:42

Surface平板

2009-12-02 09:52:46

闭包Java 7

2015-01-04 09:42:28

MDSA移动开发者服务联盟

2013-05-16 10:33:11

C#C# 5.0Async

2019-07-10 10:20:36

前端用户体验javascript

2019-04-04 14:05:20

consolejs前端

2015-08-20 09:19:46

ios9uistackview

2009-08-03 18:12:31

C#抽象类

2009-08-31 18:32:01

C# ListBoxE

2009-09-17 16:53:15

C#数组

2009-08-28 10:14:45

C#内存泄露

2015-10-21 16:47:47

Testin云测

2010-03-23 09:54:35

好压压缩

2012-09-25 09:28:36

程序员代码代码整洁

2020-05-07 10:18:06

JavaScript前端技术

2009-06-18 15:51:52

SSL VPN负载均衡Array
点赞
收藏

51CTO技术栈公众号