国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

c# 輕量級 ORM 框架 之 Model解析 (四)

2019-11-17 03:04:47
字體:
來源:轉載
供稿:網友

c# 輕量級 ORM 框架 之 Model解析 (四)

  關于orm框架設計,還有必要說的或許就是Model解析了,也是重要的一個環節,在實現上還是相對比較簡單的.

  Model解析,主要用到的技術是反射了,即:把類的屬性與表的字段做映射. 把自己的設計及實現思路寫出來也希望能有人給很好的優化建議,同時也給新手一點啟發吧.

  首先先給Model屬性定義特性,先普及一下"特性"的概念和為什么用特性(Attribute).

  簡單來說,特性是給一個類,或方法,或屬性 打上一個標記(或者叫附加信息),具體理解還是看例子比較好吧,

  在做類與表之間映射時,我們需要知道某字段的是什么類型,長度,是否主鍵,自增長,非空,等信息,最簡單較直觀的方法或許就是特性(Attribute)了,

首先我們定義一個特性,它就是一個類而已,它必須繼承自Attribute,我所寫的orm比較輕量級,僅幾個比較關鍵屬性,

代碼如下:

public class ModelAttribute : Attribute    {        /// <summary>        /// 是否主鍵        /// </summary>        public bool IsPRimaryKey  { set; get; }        /// <summary>        /// 主鍵是否自動增長        /// </summary>        public bool IsIdentity { set; get; }        /// <summary>        /// 是否非空字段        /// </summary>        public bool IsNotNull { set; get; }        /// <summary>        /// 列名        /// </summary>        public string ColumnName { set; get; }    }
View Code

下面是一個實體類使用特性的例子,它指明了Id的列名是:"Id",不允許為空的,是自增長的,是主鍵:

public class Test1 : ModelBase    {        [ModelAttribute(IsPrimaryKey = true, IsIdentity = true, IsNotNull = false, ColumnName = "Id")]        public int Id { set; get; }        public string Name { set; get; }        public string Age { set; get; }        public string Remark { set; get; }    }

下面是通過反射把Model特性解析出來,先把核心代碼貼出來:

     /// <summary>        /// 通過解析獲得Model的對象的參數,Key:為類的屬性名        /// </summary>        /// <param name="model">model對象</param>        /// <returns>返回model參數</returns>        protected override Dictionary<string, ModelAttribute> GetModelParam<TModel>()        {            var list = new Dictionary<string, ModelAttribute>();            PropertyInfo[] pros = ReflectionHelper.GetPropertyInfo<TModel>();            foreach (PropertyInfo item in pros)            {                var attr = ReflectionHelper.GetCustomAttribute<ModelAttribute>(item);                if (attr == null)                {                    //如果實體沒定義屬性則創建一個新的                    attr = new ModelAttribute();                    attr.ColumnName = item.Name;                }                else                {                    //如果列名沒有賦值,則將列名定義和屬性名一樣的值                    if (string.IsNullOrEmpty(attr.ColumnName))                    {                        attr.ColumnName = item.Name;                    }                                    }                list.Add(item.Name, attr);            }            return list;        }

因考慮反射應該是共同方法,不僅限于Model解析,所以把反射相關的方法提出來了,以下是根據"類型T"獲取自定義屬性的兩個方法:

        /// <summary>        /// 獲得指定成員的特性對象        /// </summary>        /// <typeparam name="T">要獲取屬性的類型</typeparam>        /// <param name="pInfo">屬性原型</param>        /// <returns>返回T對象</returns>        public static T GetCustomAttribute<T>(PropertyInfo pInfo) where T : Attribute, new()        {            Type attributeType = typeof(T);            Attribute attrObj = Attribute.GetCustomAttribute(pInfo, attributeType);            T rAttrObj = attrObj as T;            return rAttrObj;        }
View Code
        /// <summary>        /// 獲得對象的所有公共屬性信息        /// </summary>        /// <typeparam name="T">類型</typeparam>        /// <param name="obj">獲得的對象</param>        /// <returns>返回屬性信息</returns>        public static PropertyInfo[] GetPropertyInfo<T>() where T : class        {            Type t = typeof(T);            PropertyInfo[] proInfo = t.GetProperties();            return proInfo;        }  
View Code

解析特性我們不需要知道該類的具體實例,所以這里用了泛型,只需要知道Model類型即可,我的框架僅限于類的屬性,這里只獲取屬性的"特性對象".

返回類型Dictionary<string,ModelAttribute> Key:為屬性名,ModelAttribute 對象,

到這里解析的實現其實就完成,后面我又做了一些優化,我們想到反射時通常會聯想到效率問題,而且既然是解析一個類的特性,那么我們并不關心它的實例對象,

這里把解析出來的對象放到了緩存,即:只有第一次對該類進行反射,以后都是直接訪問緩存數據.

解析Model是一個類,那么需要做到全局緩存,我這里用到了一個靜態變量,該變量是不允許被外部更改的,所以設置為私有的了.

代碼如下:

     static object _LockObj1 = new object();        static object _LockObj2 = new object();        /// <summary>        /// 實體類緩存,靜態變量是保存為了減少反射次數        /// </summary>        static Dictionary<Type, Dictionary<string, ModelAttribute>> _ModelAttributeCache;        /// <summary>        /// 實體類緩存,靜態變量是保存為了減少反射次數        /// </summary>        protected Dictionary<Type, Dictionary<string, ModelAttribute>> ModelAttributeCache        {            get            {                if (_ModelAttributeCache == null)                {                    lock (_LockObj1)                    {                        if (_ModelAttributeCache == null)                        {                            _ModelAttributeCache = new Dictionary<Type, Dictionary<string, ModelAttribute>>();                        }                    }                }                return _ModelAttributeCache;            }        }        /// <summary>        /// 獲取Model的屬性對象,獲取第一次后會放入一個緩存列表中        /// 即只反射一次        /// </summary>        public Dictionary<string, ModelAttribute> GetModelAttribute<T>() where T : ModelBase, new()        {            Type t = typeof(T);            if (!ModelAttributeCache.ContainsKey(t))            {                lock (_LockObj2)                {                    if (!ModelAttributeCache.ContainsKey(t))                    {                        var attrs = GetModelParam<T>();                        ModelAttributeCache.Add(t, attrs);                    }                }            }            return ModelAttributeCache[t];        }

這里緩存列表為:Dictionary<Type, Dictionary<string, ModelAttribute>> ,Type即Model類的類型.

解釋一下加LockObj的意義,

我先聲明一下,這個orm框架雖然比較輕量級,但我也不是共享的一個設計階段或者或測試階段的代碼,也是經過幾個小項目使用磨合過的.

_LockObj 是在一次多線程操作時發現的bug,當多個線程訪問一個"全局對象"時,不加鎖會訪問沖突的問題.

Model解析類的路徑:ZhCun.Framework.Common.Models.TableModel

下載了代碼的可以去看下具體實現的詳細方法.

在設計DalBase 時考慮了它應依賴抽象的理念,雖然沒有想好關于Model解析除了反射還是否會有其它方法,但還是把它定義成了抽象.

到這已經完成了Model解析的功能.會再生成sql語句的時候用到它.

有了以下方法示例,估計sql文的生成就能實現了吧.

       //得到Model對象(第一次會反射,再次調用時是從緩存獲取)            Dictionary<string, ModelAttribute> modelAttr = _ModelAnaly.GetModelAttribute<T>();            //key:字段名(屬性名)            foreach (string item in modelAttr.Keys)            {                //得到列名(如果特性沒有指定ColumnName值,則與屬性名一樣)                string colName = modelAttr[item].ColumnName;                //是否字增長                bool isIdentity = modelAttr[item].IsIdentity;                //是否主鍵                bool isPrimaryKey = modelAttr[item].IsPrimaryKey;            }

關于Model解析類的實現 相對設計來說比較簡單.

如果有大神有啥好的建議,或有什么不足,希望能探討,指正 .


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 鄂尔多斯市| 应用必备| 孝义市| 津南区| 新干县| 佳木斯市| 永德县| 安泽县| 竹溪县| 招远市| 桂东县| 华池县| 高台县| 静宁县| 霍州市| 临澧县| 区。| 灵丘县| 呼图壁县| 社会| 政和县| 冕宁县| 南涧| 广昌县| 德州市| 石渠县| 喀喇| 库尔勒市| 莎车县| 神农架林区| 乐东| 舟曲县| 平阳县| 湟中县| 灵寿县| 南投县| 金堂县| 西畴县| 金山区| 临夏市| 九江市|