注冊了博客園已經有幾個月了,卻從來都沒有上來過,本人大概從2010年開始就開始做.NET 方向的開發。
這個是我在博客園發布的第一個帖子。 主要就是說說最近在寫的一個ORM架構。
本人接觸的ORM架構也有不少,沒有一個是用著順手的,要么就是配置起來特別吃力,要么就是使用起來不是很方便。 最終還是比較喜歡NHibernate這套架構,因為這套架構支持在Model表的實體類內部包含其他的表的實體類 也就是在使用的時候,連聯表查詢都可以省了 可以直接支持對象.對象的方式來進行查詢數據,屢試不爽,有了它基本已經放棄了使用視圖 或 聯表查詢等等。
但是用它也有不爽的地方,就是配置起來太麻煩,需要些HQL。
出于以上種種,想自己動手開發一套,高性能高效率的ORM架構。
廢話不多說,下面開始說我的構思。、
開發一套架構的開始,總是要有一套架構的構思的。
對于這套架構,在實體類中舍去了xml文件的配置,使用了自定義特性。
1. 用戶發起了一個添加對象的操作
2. 通過添加的該對象T,去緩存中獲取T對象相關的全部自定義特性,如果緩存中不存在則獲取該T對象的自定義特性存入緩存中
3. 找到T對象,在去緩存中獲取T-sql語句 由于數據庫不同,所以生成的Sql語句也不相同,如果不存在則新生成,然后放入緩存中。
4. 獲取到了T-SQL語句后,使用T對象生成 DbParameter[] 使用Emit,動態的創建IL 創建獲取T對象屬性的方法,來進行將T 填充到DbParameter[]
5. 通過T對應的配置文件的數據庫連接,實例化不同的數據庫
6. 實例化數據庫成功后 來進行執行插入
7. 如果插入的對象 T 是要緩存的話, 將會同時存入內存數據庫
8. 上述描述的是 添加對象 并不包含獲取對象 如果是獲取對象的話,需要用到AOP 來實現 對象.對象
太專業的話也不會說,大概的流程是這樣的一個流程,實現思路也大概有了一些,先從最底層開始寫起,那就是配置文件中的數據庫連接字符串
下面是Config 配置文件中的數據庫連接字符串
<?xml version="1.0" encoding="utf-8" ?><configuration> <connectionStrings> <add name="Lazy1" connectionString="server=.=sa;pwd=Dieyu;database=Lazy.Framework;" PRoviderName="System.Data.SqlClient"/> <add name="Lazy2" connectionString="server=.=sa;pwd=Dieyu;database=Lazy;" providerName="System.Data.SqlClient"/> </connectionStrings></configuration>
下述代碼 是先創建了 配置節點的接口
1 /// <summary> 2 /// <para>代碼說明:</para> 3 /// <para> 數據庫連接字符串接口,用戶存儲數據庫的連接字符串,主要應用于 配置文件的 connectionStrings 的節點數據庫獲取</para> 4 /// <para>使用示例:</para> 5 /// <para> 無</para> 6 /// </summary> 7 public interface ILazyConfiguration 8 { 9 /// <summary>10 /// <para>代碼說明:</para>11 /// <para> 用于設置獲取該對象的唯一標識</para>12 /// <para>使用示例:</para>13 /// <para> 無</para>14 /// </summary>15 string Name { get; set; }16 /// <summary>17 /// <para>代碼說明:</para>18 /// <para> 用于設置數據庫的連接字符串</para>19 /// <para>使用示例:</para>20 /// <para> 如:ConnectionString = "server=.;uid=sa......省略"</para>21 /// </summary>22 string ConnectionString { get; set; }23 /// <summary>24 /// <para>代碼說明:</para>25 /// <para> 用于設置該對象要連接數據庫的類型</para>26 /// <para>使用示例:</para>27 /// <para> 如:ProviderName = "System.Data.SqlClient"</para>28 /// </summary>29 string ProviderName { get; set; }30 /// <summary>31 /// <para>代碼說明:</para>32 /// <para> 用于設置該對象要連接數據庫的類型</para>33 /// <para>使用示例:</para>34 /// <para> 如:DataType = DataType.System_Data_SqlClient</para>35 /// </summary>36 LazyDataTypeEnum DataType { get; set; }37 }
下面是集成了接口的配置類
1 /// <summary> 2 /// <para>代碼說明:</para> 3 /// <para> 數據庫連接字符串對象,用戶存儲數據庫的連接字符串,主要應用于 配置文件的 connectionStrings 的節點數據庫獲取</para> 4 /// <para>使用示例:</para> 5 /// <para> 無</para> 6 /// </summary> 7 internal partial class LazyConfiguration : ILazyConfiguration 8 { 9 /// <summary>10 /// 配置節點名稱,此鍵唯一,不能擁有重復11 /// </summary>12 public string Name { get; set; }13 /// <summary>14 /// <para>代碼說明:</para>15 /// <para> 配置節點字符串</para>16 /// <para>使用示例:</para>17 /// <para> 如:ConnectionString = "server=.;uid=sa......省略"</para>18 /// </summary>19 public string ConnectionString { get; set; }20 /// <summary>21 /// <para>代碼說明:</para>22 /// <para> 配置節點要連接的數據庫驅動</para>23 /// <para>使用示例:</para>24 /// <para> 如:ProviderName = "System.Data.SqlClient"</para>25 /// </summary>26 public string ProviderName { get; set; }27 /// <summary>28 /// <para>代碼說明:</para>29 /// <para> 用于設置該對象要連接數據庫的類型</para>30 /// <para>使用示例:</para>31 /// <para> 如:DataType = DataType.System_Data_SqlClient</para>32 /// </summary>33 public LazyDataTypeEnum DataType { get; set; }34 }
當配置節點類與接口都創建完成了后 由于是多個數據庫連接串, 我們需要創捷 節點類的集合
1 /// <summary> 2 /// <para>代碼說明:</para> 3 /// <para> 配置節點訪問集合,用來獲取數據庫連接字符串的節點信息</para> 4 /// <para>使用示例:</para> 5 /// <para> 只提供程序集內部使用,外部訪問無效</para> 6 /// </summary> 7 public class LazyConfigurationCollection : IEnumerable 8 { 9 #region <<私有屬性>> 10 /// <summary> 11 /// 私有靜態集合,用于保證全局唯一性 12 /// </summary> 13 private static IList<ILazyConfiguration> listLazyConfiguration = new List<ILazyConfiguration>(); 14 #endregion 15 16 #region <<公共屬性>> 17 /// <summary> 18 /// <para>代碼說明:</para> 19 /// <para> 通過索引獲取一個ILazyConfiguration對象</para> 20 /// <para>使用示例:</para> 21 /// <para> 如:ILazyConfiguration[0]</para> 22 /// </summary> 23 /// <param name="index">索引位置</param> 24 /// <returns>ILazyConfiguration對象</returns> 25 public ILazyConfiguration this[int index] 26 { 27 get 28 { 29 return listLazyConfiguration[index]; 30 } 31 } 32 /// <summary> 33 /// <para>代碼說明:</para> 34 /// <para> 通過名稱獲取一個ILazyConfiguration對象</para> 35 /// <para>使用示例:</para> 36 /// <para> 如:ILazyConfiguration["LazySql......."]</para> 37 /// </summary> 38 /// <param name="name">要獲取連接字符串的名稱</param> 39 /// <returns>ILazyConfiguration對象</returns> 40 public ILazyConfiguration this[string name] 41 { 42 get 43 { 44 return listLazyConfiguration.FirstOrDefault(P => P.Name == name); 45 } 46 } 47 /// <summary> 48 /// <para>代碼說明:</para> 49 /// <para> 返回序列中的第一個元素;如果序列中不包含任何元素,則返回默認值。</para> 50 /// <para>使用示例:</para> 51 /// <para> 無</para> 52 /// </summary> 53 public ILazyConfiguration FirstOrDefaultConfiguration 54 { 55 get 56 { 57 return listLazyConfiguration.FirstOrDefault(); 58 } 59 } 60 /// <summary> 61 /// <para>代碼說明:</para> 62 /// <para> 返回集合的總數</para> 63 /// <para>使用示例:</para> 64 /// <para> 如:ILazyConfiguration.Count</para> 65 /// </summary> 66 public int Count 67 { 68 get 69 { 70 return listLazyConfiguration.Count; 71 } 72 } 73 #endregion 74 75 #region <<構造函數>> 76 /// <summary> 77 /// <para>代碼說明:</para> 78 /// <para> 實例化一個新的對象,該構造函數只能有程序集內部訪問</para> 79 /// <para>使用示例:</para> 80 /// <para> 無</para> 81 /// </summary> 82 internal LazyConfigurationCollection() 83 { 84 //無 85 } 86 #endregion 87 88 #region <<私有方法>> 89 /// <summary> 90 /// <para>代碼說明:</para> 91 /// <para> 向集合內添加一個對象</para> 92 /// <para>使用示例:</para> 93 /// <para> 無</para> 94 /// </summary> 95 /// <param name="item">ILazyConfiguration對象</param> 96 internal void Add(ILazyConfiguration item) 97 { 98 listLazyConfiguration.Add(item); 99 }100 #endregion101 102 #region <<公共方法>>103 /// <summary>104 /// <para>代碼說明:</para>105 /// <para> 返回一個循環訪問集合的枚舉器,可用于linq等查詢</para>106 /// <para>使用示例:</para>107 /// <para> 無</para>108 /// </summary>109 public IEnumerator GetEnumerator()110 {111 return listLazyConfiguration.GetEnumerator();112 } 113 #endregion114 }
節點集合創建完成后 , 我們需要一個單利模式, 來永遠的保存著這些節點
1 /// <summary> 2 /// <para>代碼說明:</para> 3 /// <para> 獲取配置節配置的數據庫連接字符串,該類只會被全局實例化一次</para> 4 /// <para>使用示例:</para> 5 /// <para> LazyConfigurationProperty LazyConfigurationProperty = LazyConfigurationProperty.GetLazyConfigurationProperty()</para> 6 /// </summary> 7 public sealed class LazyConfigurationProperty 8 { 9 #region <<私有屬性>>10 /// <summary>11 /// 創建全為唯一私有lazyConfigurationProperty 對象12 /// </summary>13 private static LazyConfigurationProperty lazyConfigurationProperty;14 /// <summary> 15 /// 程序運行時,創建一個靜態只讀的進程輔助對象16 /// </summary>17 private static readonly object _object = new object();18 #endregion19 20 #region <<公共屬性>>21 /// <summary>22 /// <para>代碼說明:</para>23 /// <para> 獲取配置文件的配置節的集合</para>24 /// <para>使用示例:</para>25 /// <para> 如:LazyConfigurations["xx"] or LazyConfigurations[i].....</para>26 /// </summary>27 public LazyConfigurationCollection LazyConfigurations { get; private set; }28 #endregion29 30 #region <<構造函數>>31 /// <summary>32 /// 構造方法私有,外鍵不能通過New類實例化此類33 /// </summary>34 private LazyConfigurationProperty() { }35 #endregion36 37 #region <<公共方法>>38 /// <summary>39 /// <para>代碼說明:</para>40 /// <para> 單例模式,數據庫配置對象, 全局唯一創建對象的入口</para>41 /// <para>使用示例:</para>42 /// <para> LazyConfigurationProperty LazyConfigurationProperty = LazyConfigurationProperty.GetLazyConfigurationProperty()</para>43 /// </summary>44 /// <returns>LazyConfigurationProperty全局唯一對象</returns>45 public static LazyConfigurationProperty GetLazyConfigurationProperty()46 {47 //先判斷實例是否存在,不存在再加鎖處理48 if (lazyConfigurationProperty == null)49 {50 //在同一時刻加了鎖的那部分程序只有一個線程可以進入,51 lock (_object)52 {53 //如實例不存在,則New一個新實例,否則返回已有實例54 if (lazyConfigurationProperty == null)55 {56 lazyConfigurationProperty = new LazyConfigurationProperty();57 //配置節點集合58 lazyConfigurationProperty.LazyConfigurations = new LazyConfigurationCollection();59 60 //像LazyConfigurationCollection添加對象61 var LazyConfigurationList = SettingConnectionStrings.GetConnectionStrings();62 foreach (var item in LazyConfigurationList)63 {64 lazyConfigurationProperty.LazyConfigurations.Add(item);65 }66 }67 }68 }69 return lazyConfigurationProperty;70 }71 #endregion72 }
當此上述類被構建時 , 調用了下面類的方法, 將所有連接字符串 都裝入上述類的集合中
1 /// <summary> 2 /// <para>代碼說明:</para> 3 /// <para> 配置文件對象初始化類,檢查配置文件,初始化連接對象</para> 4 /// <para>使用示例:</para> 5 /// <para> 如:SettingConnectionStrings.GetLazyConnectionStrings()</para> 6 /// </summary> 7 internal sealed class SettingConnectionStrings 8 { 9 /// <summary>10 /// <para>代碼說明:</para>11 /// <para> 獲取配置文件中的ConnectionStrings節中的全部數據中的Lazy配置集合</para>12 /// <para>使用示例:</para>13 /// <para> 如:SettingConnectionStrings.GetLazyConnectionStrings()</para>14 /// </summary>15 /// <returns>返回Lazy配置集合</returns>16 internal static IEnumerable<ConnectionStringSettings> GetLazyConnectionStrings()17 {18 //獲取全部數據庫連接19 var _ConnectionStrings = ConfigurationManager.ConnectionStrings;20 //獲取數據庫配置的連接字符串21 var _LazyConnectionStrings = _ConnectionStrings.Cast<ConnectionStringSettings>().Where(P => P.Name.IndexOf("Lazy") == 0);22 if (_LazyConnectionStrings.Count() <= 0)23 {24 //如果未配置任何連接字符串,則出現此異常25 throw new ArgumentNullException("connectionStrings", "在配置文件中, connectionStrings 節點,并不包含數據庫連接字符串的配置, 要解決此錯誤,需要在配置文件中 connectionStrings 節點內添加 /"name/" 以 Lazy 開頭的節點配置");26 }27 28 return _LazyConnectionStrings;29 }30 /// <summary>31 /// <para>代碼說明:</para>32 /// <para> 獲取配置文件中的ConnectionStrings節中的全部數據中的Lazy配置集合</para>33 /// <para>使用示例:</para>34 /// <para> 如:SettingConnectionStrings.GetConnectionStrings()</para>35 /// </summary>36 /// <returns>返回Lazy配置集合</returns>37 internal static IList<ILazyConfiguration> GetConnectionStrings()38 {39 //獲取節點集合40 var _ConnectionStringSettingsList = GetLazyConnectionStrings();41 //設置返回集合42 IList<ILazyConfiguration> _LazyConfigurationList = new List<ILazyConfiguration>();43 foreach (ConnectionStringSettings connectionStringSettings in _ConnectionStringSettingsList)44 {45 LazyDataTypeEnum _LazyDataType;46 try47 {48 //將ProviderName轉換成枚舉,如果失敗則觸發異常49 _LazyDataType = (LazyDataTypeEnum)Enum.Parse(typeof(LazyDataTypeEnum),connectionStringSettings.ProviderName.Replace('.', '_'));50 }51 catch52 {53 //如果無法轉換為枚舉 , 則引發異常.54 StringBuilder _ErrorMsg =new StringBuilder();55 _ErrorMsg.Append("在位置文件中,connectionStrings 節點下的子節點,并不包含 /"ProviderName/" 的屬性配置,或并不屬于以下的一種:/n");56 _ErrorMsg.Append("System.Data.Odbc/n");57 _ErrorMsg.Append("System.Data.OleDb/n");58 _ErrorMsg.Append("System.Data.OracleClient/n");59 _ErrorMsg.Append("System.Data.SqlClient/n");60 _ErrorMsg.Append("MySQL.Data.MySqlClient/n");61 _ErrorMsg.Append(" 要解決此問題,請按此配置,如下/n");62 _ErrorMsg.Append(" <add name=/"LazySqlConnection/" connectionString=/"server=....省略;/" providerName=/"System.Data.SqlClient/" />/n");63 throw new ArgumentNullException("ProviderName", _ErrorMsg.ToString());64 }65 66 if (_LazyConfigurationList.Count(P => P.Name == connectionStringSettings.Name) > 0)67 {68 throw new ArgumentNullException("Name", "在配置文件中, connectionStrings 節點,存在相同 /"name/" 的節點.");69 }70 71 //添加集合72 _LazyConfigurationList.Add(new LazyConfiguration()73 {74 ConnectionString = connectionStringSettings.ConnectionString,75 Name = connectionStringSettings.Name,76 ProviderName = connectionStringSettings.ProviderName,77 DataType = _LazyDataType78 });79 80 }81 return _LazyConfigurationList;82 }83 }
上面代碼是寫關于 配置連接字符串的存儲
下面再放入一個數據庫類型的枚舉
1 /// <summary> 2 /// <para>代碼說明:</para> 3 /// <para> 數據庫類型枚舉</para> 4 /// <para>使用示例:</para> 5 /// <para> LazyDataTypeEnum.SQLServer</para> 6 /// </summary> 7 public enum LazyDataTypeEnum 8 { 9 /// <summary>10 /// System.Data.Odbc11 /// </summary>12 System_Data_Odbc,13 /// <summary>14 /// System.Data.OleDb15 /// </summary>16 System_Data_OleDb,17 /// <summary>18 /// System.Data.OracleClient19 /// </summary>20 System_Data_OracleClient,21 /// <summary>22 /// System.Data.SqlClient23 /// </summary>24 System_Data_SqlClient,25 /// <summary>26 /// MySql.Data.MySqlClient27 /// </summary>28 MySql_Data_MySqlClient29 30 }
第一天,相關連接字符串的存儲 就先寫到這里 歡迎指點。
新聞熱點
疑難解答