• asp.net—自定义轻量级ORM


    大型项目中ORM的使用已经是相当的频繁。目前.NET(C#)中比较流行的ORM框架也有很多,比如SqlSugar,Dapper,Entity Framework(EF)等。

    相信很多有2年以上工作经验的园友都会使用其中一种或者几种。同时多多少少也会存在有会用却不懂其中原理的园友(我算其中一个),所以凭借

    工作之余独自钻研了一段时间,现在分享下我的钻研成果。  同时也希望园内大能者指出不足之处。

    在工作中,本人觉得写SQL 查询数据还是挺方便。所以这个轻量级的ORM中对于查询还是使用写SQL的方式

    下图就是主要的文件:

    DataFieldAttribute.cs:实体映射表字段 特性(用于标注实体类中成员属性对应数据库中的字段名和字段类型)

    PropertyAttribute.cs  :实体映射数据库表 特性(用于标注实体类对应数据库中哪个表)

    DBCrateFactory.cs    :创建数据库对象的工厂(用于创建哪种数据库对象   MS SQL   还是  ORACLE)

    SQLHelper.cs            :这是一个抽象函数。DBWorks文件夹下所有类都继承该抽象函数,这些子类就必须实现SQLHelper中的抽象方法同时也可以使用该抽象函数的公用方法

    IWiteem.cs                : 对外接口

    Witeem.cs       :继承并实现IWiteem接口

    CommonHelper.cs     :通用工具类

    DBWorks文件夹下存放的是数据库操作类(因为是DEMO,所以只设置了MS SQL和ORACLE)

    Enum文件夹下存放的是需要使用到的一些枚举类(ColumnKeyType.cs  字段状态, DBEnum.cs 数据库类型)

    下图是接口中提供的方法:

    下载地址中的代码或许还存在少部分瑕疵,在每次发现并更改过程后我及时更新。

    2018-06-26 Bug:

    1、SQLHelper类的ExecuteQueryPage函数

    2、CommonHelper类的 DataTableToObject<T> 和 DataTableToList<T>修改成根据DataFieldAttribute特性中的字段反射对应的值

    public static T DataTableToObject<T>(DataTable dt, bool IsDataField) where T : new()
            {
                Type type = typeof(T);
                string tempName = string.Empty;
                T myt = new T();
                PropertyInfo[] propertys = myt.GetType().GetProperties();
                PropertyInfo[] array = propertys;
                int i = 0;
                DataFieldAttribute attribute = null;
                PropertyAttribute proAttribute = null;
                while (i < array.Length)
                {
                    PropertyInfo pi = array[i];
                    if (IsDataField)
                    {
                        object[] infos = null;
                        object[] pros = null;
                        infos = pi.GetCustomAttributes(typeof(DataFieldAttribute), false);
                        pros = pi.GetCustomAttributes(typeof(PropertyAttribute), false);
                        if (infos.Length > 0)
                        {
                            attribute = (DataFieldAttribute)(infos[0]);
                            if (pros.Length>0)
                            {
                                proAttribute = (PropertyAttribute)(pros[0]);
                                if (proAttribute.columnKeyType != ColumnKeyType.Extend)
                                {
                                    tempName = attribute.FieldName;
                                }
                            }else
                                tempName = attribute.FieldName;
                        }
                    }
                    else
                        tempName = pi.Name;
    
                    if (dt.Columns.Contains(tempName))
                    {
                        if (pi.CanWrite)
                        {
                            object value = dt.Rows[0][tempName];
                            if (value.GetType().Equals(typeof(DateTime)))
                                value = Convert.ToString(value);
                            if (value != DBNull.Value)
                                pi.SetValue(myt, value, null);
                        }
                    }
                    i += 1;
                    continue;
                }
                return myt;
            }
    View Code
    public static List<T> DataTableToList<T>(DataTable dt, bool IsDataField) where T : new()
            {
                List<T> ts = new List<T>();
                Type type = typeof(T);
                string tempName = string.Empty;
                foreach (DataRow dr in dt.Rows)
                {
                    T myt = new T();
                    PropertyInfo[] propertys = myt.GetType().GetProperties();
                    PropertyInfo[] array = propertys;
                    int i = 0;
                    DataFieldAttribute attribute = null;
                    PropertyAttribute proAttribute = null;
                    while (i < array.Length)
                    {
                        PropertyInfo pi = array[i];
                        if (IsDataField)
                        {
                            object[] infos = null;
                            object[] pros = null;
                            infos = pi.GetCustomAttributes(typeof(DataFieldAttribute), false);
                            pros = pi.GetCustomAttributes(typeof(PropertyAttribute), false);
                            if (infos.Length > 0)
                            {
                                attribute = (DataFieldAttribute)(infos[0]);
                                if (pros.Length > 0)
                                {
                                    proAttribute = (PropertyAttribute)(pros[0]);
                                    if (proAttribute.columnKeyType != ColumnKeyType.Extend)
                                    {
                                        tempName = attribute.FieldName;
                                    }
                                }
                                else
                                    tempName = attribute.FieldName;
                            }
                        }
                        else
                            tempName = pi.Name;
                        if (dt.Columns.Contains(tempName))
                        {
                            if (pi.CanWrite)
                            {
                                object value = dr[tempName];
                                if (value.GetType().Equals(typeof(DateTime)))
                                    value = System.Convert.ToString(value);
                                if (value != DBNull.Value)
                                    pi.SetValue(myt, value, null);
                            }
                        }
                        i += 1;
                        continue;
                    }
                    ts.Add(myt);
                }
                return ts;
            }
    View Code

    2018-06-28 Bug:反射实体获取表字段时不是去特性中标注的字段名(现已修复)

    1、修改工具类中的GetTableColumns函数(注释部分为旧的代码),GetTableColumns函数也做了相应的修改

    public static List<string> GetTableColumns(PropertyInfo[] pis, ref List<PropertyInfo> proList, bool Isidentity = false)
            {
                List<string> columns = new List<string>();
                object[] infos = null;
                object[] fields = null;
                DataFieldAttribute Fieldattribute = null;
                PropertyAttribute attribute = null;
                foreach (PropertyInfo pi in pis)
                {
                    //获取此成员所有自定义特性
                    infos = pi.GetCustomAttributes(typeof(PropertyAttribute),false);
                    fields = pi.GetCustomAttributes(typeof(DataFieldAttribute), false);
                    if (fields.Length == 0)
                    {
                        continue;
                    }
                    Fieldattribute = (DataFieldAttribute)(fields[0]);
                    if (infos.Length > 0)
                    {
                        attribute = (PropertyAttribute)(infos[0]);
                        if (attribute == null)
                        {
                            //columns.Add(pi.Name);
                            columns.Add(Fieldattribute.FieldName);
                            proList.Add(pi);
                        }
                        else
                        {
                            switch (attribute.columnKeyType)
                            {
                                case ColumnKeyType.Extend: break;
                                case ColumnKeyType.Identity:
                                    {
                                        if (Isidentity)
                                        {
                                            //columns.Add(pi.Name);
                                            columns.Add(Fieldattribute.FieldName);
                                            proList.Add(pi);
                                        }
                                    }; break;
                                default:
                                    {
                                        //columns.Add(pi.Name);
                                        columns.Add(Fieldattribute.FieldName);
                                        proList.Add(pi);
                                    };
                                    break;
                            }
                        }
                    }
                }
                return columns;
            }
    View Code

    2、MSSql.cs类 对于上述BUG做了修改

    public override int Add<T>(IEnumerable<T> obj)
            {
                try
                {
                    int i = 0;
                    int result = 0;
                    int success = 0;
                    //Type type = obj.GetType();
                    Type type = typeof(T);
                    //获取表名
                    string tableName = CommonHelper.GetTableName(type);
                    PropertyInfo[] pis = type.GetProperties();
                    //获取所有字段,和主键名称
                    List<string> columns = null;
                    List<PropertyInfo> proList = new List<PropertyInfo>();
                    columns = CommonHelper.GetTableColumns(pis,ref proList, false);
                    //处理是否包含主键插入
                    //if (isIdentity)
                    //{
                    //    columns = CommonHelper.GetTableColumns(pis, true);
                    //}
                    //else
                    //{
                    //    columns = CommonHelper.GetTableColumns(pis, false);
                    //}
                    foreach (T item in obj)
                    {
                        //生成SQL语句
                        StringBuilder sqlText = new StringBuilder();
                        sqlText.Append(" INSERT INTO ");
                        sqlText.Append(tableName);
                        sqlText.Append(" (");
                        //第一个字段
                        sqlText.Append(columns[0]);
                        //第二个起所有字段
                        int loop = columns.Count;
                        for (i = 1; i < loop; i++)
                        {
                            sqlText.Append(",");
                            sqlText.Append(columns[i]);
                        }
                        sqlText.Append(") VALUES (");
                        //第一个字段
                        sqlText.Append("@");
                        sqlText.Append(columns[0]);
                        //第二个起所有字段
                        for (i = 1; i < loop; i++)
                        {
                            sqlText.Append(",@");
                            sqlText.Append(columns[i]);
                        }
                        sqlText.Append(");");
                        //生成SqlParamter
                        PropertyInfo propertyInfo = null;
                        List<SqlParameter> paras = new List<SqlParameter>();
                        for (i = 0; i < loop; i++)
                        {
                            propertyInfo = proList[i];
                            SqlParameter para = new SqlParameter(columns[i], CommonHelper.GetSqlType(propertyInfo.PropertyType), -1);
                            para.Value = propertyInfo.GetValue(item);
                            paras.Add(para);
                        }
                        result = ExecuteNonQuery(sqlText.ToString(), CommandType.Text, paras, false);
                        if (result > 0)
                        {
                            success += 1;
                        }
                    }
                    if (conn.State == ConnectionState.Open)
                    {
                        ConColsed();
                    }
                    return success;
                    
                }
                catch (Exception ex)
                {
                    execlog.Debug(DateTime.Now.ToString() + ": Add失败,原因【" + ex.ToString() + "");
                    return -1;
                }
            }
    View Code
    public override int Delete<T>(IEnumerable<T> obj)
            {
                try
                {
                    int result = 0;
                    int success = 0;
                    //Type type = obj.GetType();
                    Type type = typeof(T);
                    //获取表名
                    string tableName = CommonHelper.GetTableName(type);
                    PropertyInfo[] pis = type.GetProperties();
                    PropertyInfo identityInfo = null;
                    identityInfo = CommonHelper.GetTableIdentity(pis);
                    string identityName = CommonHelper.GetIdentityName(pis);
                    if (identityInfo == null)
                    {
                        return 0;
                    }
                    if (string.IsNullOrEmpty(identityName))
                    {
                        identityName = identityInfo.Name;
                    }
                    foreach (T item in obj)
                    {
                        //生成SQL语句
                        StringBuilder sqlText = new StringBuilder();
                        sqlText.Append(" DELETE FROM ");
                        sqlText.Append(tableName);
                        sqlText.Append(" WHERE 1=1 ");
                        //主键筛选
                        sqlText.Append(" AND " + identityName);
                        sqlText.Append("=@" + identityName);
                        //生成SqlParamter
                        List<SqlParameter> paras = new List<SqlParameter>();
                        SqlParameter para = new SqlParameter(identityName, CommonHelper.GetSqlType(identityInfo.PropertyType), -1);
                        para.Value = identityInfo.GetValue(item);
                        paras.Add(para);
                        result = ExecuteNonQuery(sqlText.ToString(), CommandType.Text, paras,false);
                        if (result>0)
                        {
                            success += 1;
                        }
                    }
                    if (conn.State == ConnectionState.Open)
                    {
                        ConColsed();
                    }
                    return success;
                }
                catch (Exception ex)
                {
                    execlog.Debug(DateTime.Now.ToString() + ": Delete失败,原因【" + ex.ToString() + "");
                    return -1;
                }
            }
    View Code
    public override int Update<T>(IEnumerable<T> obj)
            {
                try
                {
                    int i = 0;
                    int result = 0;
                    int success = 0;
                    //Type type = obj.GetType();
                    Type type = typeof(T);
                    //获取表名
                    string tableName = CommonHelper.GetTableName(type);
                    PropertyInfo[] pis = type.GetProperties();
                    //获取所有字段,和主键名称
                    string identityName = CommonHelper.GetIdentityName(pis);
                    //获取主键名称
                    PropertyInfo identityInfo = null;
                    identityInfo = CommonHelper.GetTableIdentity(pis);
                    if (identityInfo == null)
                    {
                        return 0;
                    }
                    if (string.IsNullOrEmpty(identityName))
                    {
                        identityName = identityInfo.Name;
                    }
                    List<string> columns = null;
                    List<PropertyInfo> proList = new List<PropertyInfo>();
                    //获取所有字段名称
                    columns = CommonHelper.GetTableColumns(pis, ref proList, true);
                    foreach (T item in obj)
                    {
                        //生成SQL语句
                        StringBuilder sqlText = new StringBuilder();
                        int loop = columns.Count;
                        sqlText.Append(" UPDATE ");
                        sqlText.Append(tableName);
                        sqlText.Append(" SET ");
                        //第二个起所有字段
                        for (i = 0; i < loop; i++)
                        {
                            //判断第一个字段是否为主键
                            if (columns[i] == identityName)
                            {
                                continue;
                            }
                            sqlText.Append(columns[i] + "=@" + columns[i]);
                            if (i < loop - 1)
                            {
                                sqlText.Append(",");
                            }
                        }
                        //主键筛选
                        sqlText.Append(" WHERE " + identityName);
                        sqlText.Append("=@" + identityName);
                        //生成SqlParamter
                        List<SqlParameter> paras = new List<SqlParameter>();
                        PropertyInfo propertyInfo = null;
                        for (i = 0; i < loop; i++)
                        {
                            propertyInfo = proList[i];
                            SqlParameter para = new SqlParameter(columns[i], CommonHelper.GetSqlType(propertyInfo.PropertyType), -1);
                            para.Value = propertyInfo.GetValue(item);
                            paras.Add(para);
                        }
                        result = ExecuteNonQuery(sqlText.ToString(), CommandType.Text, paras,false);
                        if (result>0)
                        {
                            success += 1;
                        }
                    }
                    if (conn.State == ConnectionState.Open)
                    {
                        ConColsed();
                    }
                    return success;
                }
                catch (Exception ex)
                {
                    execlog.Debug(DateTime.Now.ToString() + ": Update失败,原因【" + ex.ToString() + "");
                    return -1;
                }
    
            }
    View Code
    public override T GetModel<T>(string id)
            {
                int i = 0;
                Type type = typeof(T);
                T myT = new T();
                //获取表名
                string tableName = CommonHelper.GetTableName(type);
              
                PropertyInfo[] pis = type.GetProperties();
                PropertyInfo identityInfo = null;
                identityInfo = CommonHelper.GetTableIdentity(pis);
                string identityName = CommonHelper.GetIdentityName(pis);
                if (identityInfo == null)
                {
                    return default(T);
                }
                if (string.IsNullOrEmpty(identityName))
                {
                    identityName = identityInfo.Name;
                }
                //获取所有字段,和主键名称
                List<string> columns = null;
                List<PropertyInfo> proList = new List<PropertyInfo>();
                //获取所有字段名称
                List<ColumnKeyType> filterList = new List<ColumnKeyType>();
                filterList.Add(ColumnKeyType.Default);
                filterList.Add(ColumnKeyType.Read);
                filterList.Add(ColumnKeyType.Identity);
                columns = CommonHelper.GetTableColumns(pis, ref proList, true);
                //生成SQL语句
                StringBuilder sqlText = new StringBuilder();
                sqlText.Append(" SELECT ");
                //第一个字段
                sqlText.Append(columns[0]);
                //第二个起所有字段
                int loop = columns.Count;
                for (i = 1; i < loop; i++)
                {
                    sqlText.Append(",");
                    sqlText.Append(columns[i]);
                }
                sqlText.Append(" FROM ");
                sqlText.Append(tableName);
                sqlText.Append(" WHERE 1=1 AND ");
                sqlText.Append(identityName + "=@" + identityName);
                //生成SqlParamter
                List<SqlParameter> paras = new List<SqlParameter>();
                SqlParameter para = new SqlParameter(identityName, CommonHelper.GetSqlType(identityInfo.PropertyType), -1);
                para.Value = id;
                paras.Add(para);
                return GetModel<T>(sqlText.ToString(), CommandType.Text, paras);
            }
    View Code

    3、事务处理应先打开数据库连接

    2018-12-13 获取所有字段名称的地方加入缓存机制,目的是避免每次执行都需要去获取字段名称数据集,提高效率:

    Update 和 GetModel 方法的缓存机制

    //获取所有字段名称(缓存处理)
    if (CacheHelper.GetCache(tableName) != null)
    {
          columns = (List<string>)CacheHelper.GetCache(tableName);
    }
    else
    {
          columns = CommonHelper.GetTableColumns(pis, ref proList, true);
          CacheHelper.SetCache(tableName, columns, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(60));
    }

    Add方法的缓存机制:

     //获取所有字段名称(缓存处理)
    if (CacheHelper.GetCache(tableName + isIdentity.ToString()) != null)
    {
        columns = (List<string>)CacheHelper.GetCache(tableName + isIdentity.ToString());
    }
    else
    {
        columns = CommonHelper.GetTableColumns(pis, ref proList, isIdentity);
        CacheHelper.SetCache(tableName + isIdentity.ToString(), columns, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(60));
    }

    github下载地址:https://github.com/witeem/ASP.NET-ORM.git

  • 相关阅读:
    Python 包的概念
    EXCEL基础篇(二)
    EXCEL基础篇(一)
    JavaScript(四)Bom
    JavaScript(三)Dom查找、设置标签属性及内容、绑定事件
    erlang并发编程(二)
    OTP&ETS
    erlang中http请求
    erlang证书加密
    erlang并发编程
  • 原文地址:https://www.cnblogs.com/witeem/p/9214195.html
Copyright © 2020-2023  润新知