您好,登錄后才能下訂單哦!
最近一直在忙新公司的基礎庫建設,對系統架構、開發框架及快速開發平臺的設計實施都積累了一定的實踐經驗。
一般的中小型的軟件開發公司,如果按照技術儲備來衡量軟件項目的技術含量的評定依據是可行的。但如果光是按照人頭來衡量軟件的技術含量是不可靠的。所以我們在選擇跳巢的時候是選擇大公司還是選擇有技術含量的公司要根據自己的職業規劃來。(本人最近體會到的一點跳巢經驗分享給大家)
由于我現有單位技術部門剛剛成立不久,需要一些基礎的開發框架,ORM當然是跑不了的。在后面的文章中我將陸續寫下我在建設基礎框架中的一些實踐檢驗,里面可能包括對UI層的封裝、基礎控件的封裝等等。我就廢話少扯了,進入主題。
這篇文章的重點是無反射的ORM框架,為什么會有這樣的想法?其實前不久群里的朋友就問了一些問題,他們在構建自己的ORM框架的時候頻繁的在使用反射來編寫功能。從跟他們的交流上來看他們似乎很喜歡使用反射來寫功能,但是沒有仔細的研究過ORM框架的作用是在系統架構的哪個位置,在對性能要求十分嚴格的情況下反射會有點無能為力。
反射的好處當然是毋庸置疑的,一些技術稍微好點的或者大牛們通常會用動態編譯的技術來平滑的過度這個系統最重要的性能瓶頸點。我總覺的可以用高層的抽象和約定來解決這個ORM使用反射的問題。下面我們來分析一下通常ORM框架為什么需要用反射,反射的目的是什么。[王清培版權所有,轉載請給出署名]
當然我們這里討論的是最普通的問題也是必須的問題。
ORM框架的種類形態各異,不同的公司不同的ORM實現。其實目的是為了能有一套屬于自己公司的開發框架,這不是技術所定而是公司高層領導所要求的。(我們沒有說話的權利,為了保住飯碗,我們只能聽從指揮)
但是大部分的ORM框架的設計思想和實現思路都離不開那幾點的“思維實現約束”。我為什么要說“思維實現約束”,這也是我們程序員的一些通病之一吧,都喜歡用復雜的技術。不管三七二十一用了心里舒服。這是好事,為了練習技術可以理解。沒有這份好奇心這份激情我們也很難走到專家的位置。
目的之一:為了表達實體與表的對應關系
ORM是實體與表的一種映射關系,逐漸被發展為一種復雜的技術實現模型。
在傳統的分層架構中,在實體的定義上都會使用一個特性來標記該實體所表示的表名稱是什么。如:
[Serializable()]
[HZ.Table(TableName = "member")]
public class Member{}
特性HZ.Table中的屬性TableName來保存靜態的表名,在ORM中通過獲取對象的類型然后反射出該類型的特性元數據。然后讀取相關成員屬性值,作為拼接SQL語句的必備條件。
目的之二:為了表達屬性與字段的對應關系及一些主、外鍵
ORM中將實體的屬性映射成數據庫中表的字段,一般通過兩種方式來表達這中關系。
第一種:通過屬性特性來表示該屬性代表的字段名稱;
[HZ.Column(PrimaryKey = true,ColumnName=”MemberId”)]
public string MemberCode { get; set; }
第二種:直接通過屬性名稱來表示字段的名稱;
public string MemberId { get; set; }
目的之三:獲取實體屬性中的值
在進行插入或更新的時候需要獲取實體中的屬性的值,這個時候只能使用反射的方式獲取到屬性的值,然后拼接插入或更新語句。
目的之四:設置實體屬性的值
通過實例化泛型對象,然后反射對象的屬性通過SetValue方法設置屬性的值。
簡結:這幾點是最常用的,可能還包括其他復雜的功能,這里我就不涉及了。上面這幾點都是通過反射獲取實體的信息,不管是增、刪、改、查都需要反射。尤其是對于查詢數據來說,如果是大數據量的查詢性能問題很嚇人。
通過抽象、多態設計不需要特性的ORM實體
大部分ORM框架是需要代碼生成器做支持的,不是所有的代碼都是需要程序員手動去敲的,可以通過一些模板引擎類的代碼生成器,編輯好自己的模板然后生成大部分的實體代碼。包括.NET里面的EntityFramework、LinqToSql也是用IDE集成的代碼生成器。
所以這里就會涉及到對企業代碼生成器的考慮,這里就先不扯了,后續文章我們再來針對性討論。
那么我們先來討論如何設計實體結構,讓它能包含我們ORM所需要的必備信息。其實我們的思路稍微轉變一下利用抽象來解決問題。提高抽象層次,將實體視為兩個層面。頂層抽象類被ORM使用,子類被調用者使用。
圖:
我們的要求就是ORM中不能存在一個反射的代碼。所以我們約定了BasicEntityObject抽象類,通過定義頂層抽象基類來包含子類所要用到的一些屬性信息。
我們看一下抽象類中包含了哪些東西。
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Collections;
- namespace Glory.Net.ORM
- {
- public abstract class BaseEntityObject : DictionaryBase
- {
- /// <summary>
- /// 實體對象對應數據庫中的表名
- /// </summary>
- private string _tablename = string.Empty;
- /// <summary>
- /// 受保護字典:實體類中對應數據庫表中主鍵的屬性和屬性類型
- /// </summary>
- protected Dictionary<string, string> _primarydictionary = new Dictionary<string, string>();
- /// <summary>
- /// 用于實體子類設置當前子類對應數據庫中的表名
- /// </summary>
- protected string TableName
- {
- get { return _tablename; }
- set { _tablename = value; }
- }
- /// <summary>
- /// 客戶代碼獲取當前實例對應ORM中的表名
- /// </summary>
- public string GetTableName
- {
- get { return _tablename; }
- }
- /// <summary>
- /// 用于實體子類設置當前實例的屬性值
- /// </summary>
- /// <param name="key"></param>
- /// <returns></returns>
- protected object this[string key]
- {
- get { return this.Dictionary[key]; }
- set { this.Dictionary[key] = value; }
- }
- /// <summary>
- /// 設置實例的屬性值
- /// </summary>
- /// <param name="key">屬性名稱</param>
- /// <param name="value">屬性值</param>
- public void SetEntityVlues(string key, object value)
- {
- if (this.Dictionary.Contains(key))
- {
- this.Dictionary[key] = value;
- }
- }
- /// <summary>
- /// 獲取實例的屬性鍵值隊
- /// </summary>
- /// <returns></returns>
- public IDictionary GetEntityValue
- {
- get{return (IDictionary)this.Dictionary;}
- }
- /// <summary>
- /// 獲取實例的主鍵信息
- /// </summary>
- public IDictionary GetEntityPrimary
- {
- get { return (IDictionary)_primarydictionary; }
- }
- protected abstract void AddPrimaryToDictionary();
- }
- }
其實代碼很簡單,就是為了將子類的屬性值保存到基類中來,讓子類只是一個空殼子。
- public class Tb_Car : VluesInitTb_Car
- {
- /// <summary>
- /// 唯一主鍵
- /// </summary>
- public string CID
- {
- get { return this["CID"] as string; }
- set { this["CID"] = value; }
- }
- /// <summary>
- /// 車牌號
- /// </summary>
- public string CarBanrdCode
- {
- get { return this["CarBanrdCode"] as string; }
- set { this["CarBanrdCode"] = value; }
- }
- /// <summary>
- ///
- /// </summary>
- public string CarCode
- {
- get { return this["CarCode"] as string; }
- set { this["CarCode"] = value; }
- }
- /// <summary>
- ///
- /// </summary>
- public string DriverName
- {
- get { return this["DriverName"] as string; }
- set { this["DriverName"] = value; }
- }
- /// <summary>
- /// 聯系電話
- /// </summary>
- public string Mobile
- {
- get { return this["Mobile"] as string; }
- set { this["Mobile"] = value; }
- }
- /// <summary>
- /// 車型
- /// </summary>
- public string CarType
- {
- get { return this["CarType"] as string; }
- set { this["CarType"] = value; }
- }
- /// <summary>
- /// 購車日期
- /// </summary>
- public DateTime? BuyDateTime
- {
- get { return this["BuyDateTime"] as DateTime?; }
- set { this["BuyDateTime"] = value; }
- }
- /// <summary>
- /// 所屬中心編號。外鍵
- /// </summary>
- public string AttachCenter
- {
- get { return this["AttachCenter"] as string; }
- set { this["AttachCenter"] = value; }
- }
- /// <summary>
- /// 所屬區部編號。外鍵
- /// </summary>
- public string AttachSection
- {
- get { return this["AttachSection"] as string; }
- set { this["AttachSection"] = value; }
- }
- /// <summary>
- /// 所屬站點編號。外鍵
- /// </summary>
- public string AttachStop
- {
- get { return this["AttachStop"] as string; }
- set { this["AttachStop"] = value; }
- }
- }
那么中間的類是干嘛用的呢,是為了將初始化隔離在基類中;
- [Serializable()]
- public class VluesInitTb_Car : BaseEntityObject
- {
- public VluesInitTb_Car()
- {
- this.TableName = "Tb_Car";
- /// <summary>
- /// 唯一主鍵
- /// </summary>
- this.Dictionary.Add("CID", null);
- /// <summary>
- /// 車牌號
- /// </summary>
- this.Dictionary.Add("CarBanrdCode", null);
- /// <summary>
- ///
- /// </summary>
- this.Dictionary.Add("CarCode", null);
- /// <summary>
- ///
- /// </summary>
- this.Dictionary.Add("DriverName", null);
- /// <summary>
- /// 聯系電話
- /// </summary>
- this.Dictionary.Add("Mobile", null);
- /// <summary>
- /// 車型
- /// </summary>
- this.Dictionary.Add("CarType", null);
- /// <summary>
- /// 購車日期
- /// </summary>
- this.Dictionary.Add("BuyDateTime", null);
- /// <summary>
- /// 所屬中心編號。外鍵
- /// </summary>
- this.Dictionary.Add("AttachCenter", null);
- /// <summary>
- /// 所屬區部編號。外鍵
- /// </summary>
- this.Dictionary.Add("AttachSection", null);
- /// <summary>
- /// 所屬站點編號。外鍵
- /// </summary>
- this.Dictionary.Add("AttachStop", null);
- AddPrimaryToDictionary();
- }
- /// <summary>
- /// 實體類 重寫實體基類添加主鍵信息方法,主鍵數據類型首字母要大寫
- /// </summary>
- protected override void AddPrimaryToDictionary()
- {
- _primarydictionary.Add("CID", "string");
- }
- }
通過這種層次的抽象可以很好的規避特性帶來的性能問題。在ORM中我們的泛型方法都是約束實體為BaseEntityObject類型,然后所有的信息包括主鍵、字段、數據類型都能夠通過多態的方式獲取到。
ORM通過實例化一個對象的實例然后將其緩存起來,作為后續使用。而不需要頻繁的實例化中間對象帶來的性能問題。
其實大部分的代碼都是可以通過代碼生成器生成的,我們也正在為公司開發符合自己公司產品的代碼生成器,包括對業務代碼的高度抽象、業務建模后的代碼生成。
當然該篇文章只是簡單的講解了一下核心的內容,也算是拋磚引玉吧。希望對大家來說有點啟發作用。[王清培版權所有,轉載請給出署名]
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。