首先、園子裏面以前的不少同仁已經討論過了ORM相關的框架及其優勢和缺點。雖然我本篇討論的有點晚,可是其畢竟優勢大於缺點,本文只是簡單的介紹我討html
論ORM的目的,及爲何要討論這個已經被你們討論的成熟的不能再成熟的東西。sql
咱們先來看看ORM的優缺點:數據庫
本篇將詳細分析爲何咱們要使用ORM,及ORM前篇的分析建模。框架
本篇主要是分析ORM框架的優缺點及項目中的取捨,找到突破點,而且經過圖形化的方式分析ORM應該具有的基本功能及如何構建ORM中的核心模塊。這裏面簡單函數
列舉出ORM中的核心模塊:性能
下面將分別講解和分析實現方案。測試
一、摘要。優化
二、本章簡介。ui
三、本章內容。this
四、ORM的應用性分析。
五、ORM設計分析。
六、本章總結。
七、系列進度。
八、下篇預告。
首先、在軟件開發中咱們都知道OO面向對象的思想對咱們現有的軟件開發意義,咱們能夠把軟件開發的過程理解爲將現實社會的抽象過程。面向對象的思想把現
實世界抽象爲萬物皆爲對象,經過對象之間的交互完成全部的活動。OO出現以前的軟件開發都是面向過程的開發思想。面向過程關係的是過程而不是對象。在某個動做
過程當中的步驟,經過一系列的函數來解決問題。
面向對象則把一切事物看做對象,而過程就是對象之間的交互或是對象內部的活動。
咱們知道目前流行的數據庫都是關係型數據庫,二維的數據庫結構。咱們如何將某個對象與這個實體對應起來呢?這就成了咱們更關心的問題,這時候ORM思想
的出現解決了這樣的問題。
上圖反映了實體對象與數據庫表的關係,一個實體對象對應數據庫表中的一個行記錄。而經過DDL操做中的查詢方法,來將數據庫表中的行紀錄映射到多個實體對
象中。而經過ORM提供的DDL操做方法,將實體對象的數據持久化到對應的數據庫表中。
另一個須要注意的問題就是當實體中的屬性添加或減小時或是數據庫表中的結構發生變化時,如何作到實體中的屬性與數據庫表中的列一一對應這是個每一個ORM
頭疼的問題,由於ORM沒法實現自動的同步這樣的變化。固然目前的大名鼎鼎的Nhibernate在這方面也是處理的比較靈活,這是必須確定的。固然在這個系列中咱們也
會詳細的講解實現的思路與方案,如何處理實體與數據庫表結構發生變化時的同步問題,固然這和採用的ORM的實現方式有關。
ORM思想給我提供了以下的方便:
固然ORM框架也不是萬能的,有優勢的必然存在這必定的缺點,咱們來看看ORM的不足:
經過上面的分析咱們簡單的瞭解了ORM的優缺點,那麼如何在項目中應用它呢,咱們在使用某個技術時確定是揚長避短,因此ORM也是同樣的道理,若是咱們在項目中有大量的DDL操做語句,而且對業務邏輯之間的多實體間的關聯關係不是特別的緊密時,那麼用ORM技術就會比較好。
若是在項目中多表的關聯查詢比較多,而且表之間的邏輯關係比較複雜時就不推薦用ORM來處理。不但會提升項目的複雜度,維護起來代價也比較大。例如像統
計分析系統。用ORM來實現就比較麻煩。
首先咱們來看看數據庫訪問的通用組件模型:
上圖大概畫出了比較經常使用的幾類數據庫,經過ORM中的數據庫訪問組件來實現數據庫的訪問。固然咱們這裏經過定義數據庫訪問統一接口的形式,讓全部的數據
庫訪問類都默認繼承實現這個接口。
實例代碼以下:
public interface IDBAccessor { /// <summary> /// 執行Update,Delete,Insert語句方法 /// </summary> /// <returns>返回影響的行數</returns> int Excute(); /// <summary> /// 執行查詢方法 /// </summary> void Query(); }
接口中只是定義了簡單的DDL語言中的四個基本的操做。
下面看每一個不一樣數據庫的實現方法。
SQLServer數據庫
public class SQLServer : IDBAccessor { #region IDBAccessor 成員 private string commandStr = string.Empty; private static string connectionString = ""; private System.Data.IDbConnection sqlConnection = new System.Data.SqlClient.SqlConnection(connectionString); public int Excute() { if (sqlConnection.State != System.Data.ConnectionState.Open) sqlConnection.Open(); try { using (System.Data.IDbCommand command = sqlConnection.CreateCommand()) { command.CommandText = commandStr; return command.ExecuteNonQuery(); } } catch(System.Exception) { return -1; } finally { } } public void Query() { } #endregion }
Oracle數據庫
public class Oracle : IDBAccessor { #region IDBAccessor 成員 private string commandStr = string.Empty; private static string connectionString = ""; private System.Data.IDbConnection oraConnection = new System.Data.OracleClient.OracleConnection(connectionString); public int Excute() { if (oraConnection.State != System.Data.ConnectionState.Open) oraConnection.Open(); try { using (System.Data.IDbCommand command = oraConnection.CreateCommand()) { command.CommandText = commandStr; return command.ExecuteNonQuery(); } } catch (System.Exception) { return -1; } finally { } } public void Query() { throw new NotImplementedException(); } #endregion }
其餘的幾個類型的數據庫咱們就不一一舉例說明了,固然我這裏面的接口中並無考慮把數據庫鏈接也定義成接口,讓全部的都從這個接口進行繼承,由於這個不是
本章討論的重點,本章只是簡單的分析與設計如何實現通用把數據層訪問。
下面咱們來講說對象關係映射的實現。
咱們比較常見的方式目前就這樣的2種方式,第一種方式想必你們都比較瞭解的,不管是JAVA中的Hibernate仍是.NET中的Nhibernate都是這樣的方式,以XML文
件的方式把數據庫中的表列屬性與實體的屬性一一對應。第二種方式則是在類文件中硬編碼書寫數據庫列與實體之間的映射關係。
下面咱們來分析下這二種方式的利弊:
以上大概描述了各自的有點,下面再闡述下各自的缺點。
固然以上的2種形式各有優缺點,咱們已經講述了XML配置文件中現有的開源框架中採用這種形式的框架有Nhibernate。而採用類文件映射的框架其實有不少,但
是他們的思想相對來講都是同樣的。不論是XML文件形式,仍是類文件形式,他們的主要觀點都是實現如何把實體的屬性與數據庫表字段的對應,這個纔是核心的內容。
下面咱們給出一種簡單的思路去完成這樣的映射,固然咱們這裏是以類文件形式給出示例。
其實博客園的不少人都寫過類文件映射的實例。我這裏固然也只是拋磚引玉,不足之處在所不免,還請你們多多提出意見。
我給出的方式是經過特性(Attribute)+反射(Rflection)的思想來實現ORM映射。
具體相應代碼以下:
/// <summary> /// Model中的字段屬性特性 /// </summary> [AttributeUsage(AttributeTargets.All, AllowMultiple = false)] public class PropertyAttribute : Attribute { private string dbColumnName; private bool isPrimary; private DbType dbType; private object defaultValue; private bool isIdentify; private int length; public string DbColumnName { get { return this.dbColumnName; } set { this.dbColumnName = value; } } public bool IsPrimary { get { return this.isPrimary; } set { this.isPrimary = value; } } public bool IsIdentify { get { return this.isIdentify; } set { this.isIdentify = value; } } public DbType DbType { get { return this.dbType; } set { this.dbType = value; } } public object DefaultValue { get { return this.defaultValue; } set { this.defaultValue = value; } } public int DbLength { get { return this.length; } set { this.length = value; } } public PropertyAttribute(string dbName, bool isPrimery, DbType type,object dValue) { this.dbColumnName = dbName; this.isPrimary = isPrimery; this.dbType = type; this.defaultValue = this.GetDefaultValue(); } private object GetDefaultValue() { return new object(); } public PropertyAttribute(string dbName) { this.dbColumnName = dbName; this.isPrimary = false; this.dbType = DbType.String; this.defaultValue = this.GetDefaultValue(); } public PropertyAttribute(string dbName,bool isPrimery) { this.dbColumnName = dbName; this.isPrimary = isPrimery; this.dbType = DbType.String; this.defaultValue = this.GetDefaultValue(); } public PropertyAttribute(string dbName, bool isPrimery, DbType type) { this.dbColumnName = dbName; this.isPrimary = isPrimery; this.dbType = type; this.defaultValue = null; } }
上面給出的是字段屬性上定義的特性,咱們來看看錶的特性:
/// <summary> /// 基於表的自定義特性類 /// </summary> [AttributeUsage(AttributeTargets.All, AllowMultiple = false)] public class TableAttribute : Attribute { private string dbTableName; public TableAttribute(string dbName) { this.dbTableName = dbName; } public string TableName { get { return this.dbTableName; } set { this.dbTableName = value; } } }
在實體層的具體使用以下:
/// <summary> /// 管理員帳戶ID /// </summary> [PropertyAttribute("",false,System.Data.DbType.Int32,0)] public int AdminId { set { _adminid = value; } get { return _adminid; } }
基於表上的特性以下使用:
[TableAttribute("es_memberaccount")] public class Account { public Account() { } }
下面看看如何在生成SQL語句層中的處理方法:
/// <summary> /// 返回Model對應的數據庫表名 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="model"></param> /// <returns></returns> public string DbTableName<T>(T model) { string dbName = string.Empty; DPM.Common.TableAttribute attr = null; object[] attributes = model.GetType().GetCustomAttributes(typeof(DPM.Common.TableAttribute), true); if (attributes.Length > 0) { attr = (DPM.Common.TableAttribute)attributes[0]; } if (attr != null) dbName = attr.TableName; return dbName; } /// <summary> /// 返回數據庫表中的全部數據列 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="model"></param> /// <returns></returns> public string InitDbColumns<T>(T model) { StringBuilder commandBuilder = new StringBuilder(); DPM.Common.PropertyAttribute attr = null; foreach (PropertyInfo property in model.GetType().GetProperties()) { object[] attributes = property.GetCustomAttributes(typeof(DPM.Common.PropertyAttribute), true); if (attributes.Length > 0) { attr = (DPM.Common.PropertyAttribute)attributes[0]; } commandBuilder.Append(attr.DbColumnName+」,」); } return commandBuilder.ToString().Substring(0,commandBuilder.ToString().Length-1); }
本章簡單講述了ORM實現的基本思路分析及ORM框架使用的優缺點及在項目中如何合理的分析與應用。下面咱們來簡單總結下本章講解的內容。
本章主要講述了ORM的優勢:減小工做流,複用性高,開發速度快,更關注業務方面的開發,將DDL操做中除了聯合查詢實現起來比較複雜外,其餘的基本上都
能正常的處理。缺點:一對多或者多對多的關聯關係沒法很好的知足需求外,還有就是性能上會有必定的影響。在項目中應根據項目的業務需求來決定是否在項目中使
用ORM框架來解決問題。
二、Step by Step-構建本身的ORM系列-數據訪問層
三、Step by Step-構建本身的ORM系列-配置管理層
四、Step by Step-構建本身的ORM系列-對象映射層[上]
五、Step by Step-構建本身的ORM系列-對象映射層[中]
六、Step by Step-構建本身的ORM系列-對象映射層[下]
七、Step by Step-構建本身的ORM系列-測試ORM框架
八、Step by Step-構建本身的ORM系列-瓶頸、優化
九、Step by Step-構建本身的ORM系列-實例
下篇咱們將講解如何實現通用的數據訪問層,將會詳細的介紹如何設計出通用的數據訪問層,而且採用設計模中的2個原則:低耦合、高內聚等一些設計規範和原
則。歡迎你們拍磚和提出好的意見和建議。