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

 


免責聲明!

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



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