讓C#開發更簡單,抽象增刪改


  相信經常做一些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 - 1, 1);
            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 > 0)
            {
                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 0;
        } 
        #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 = 100,ClassesId = 1,Code = "3200020021",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 == 100);
            //不帶參數查詢
            var studentInfoList = stu.QueryInfo(); 
            #region 更新
            newModel.Code = "1111111111";
            newModel.Id = StudentId;
            stu.Update(newModel);
            #endregion
          // 刪除
            stu.Delete(new string[] { newModel.Id.ToString() });         
            Console.ReadKey();
        }
    }
}

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

 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM