微型项目实践(8):数据访问的实现
上一篇文章,我們分析了數據訪問是如何定義,以及如何與其它(特別是Business)模塊耦合的,今天我們來看一下數據訪問(DataAccess)是如何實現的。
從系統結構圖和上一篇“數據訪問的定義”中可以知道,數據訪問層的任務就是實現IEntityDataAccess和IDatabase接口。由于Linq的出現,我們只需要一個Adapter,將Linq2Sql的類適配到IEntityDataAccess就可以了,其類設計圖和文件結構如下如下:
從圖中可以看到,Database類繼承與DataContext,而實現了IDatabase接口;EntityDataAccessAdapter使用System.Data.Linq.Table這個Linq的核心類實現了IEntityDataAccess接口。
Database類的代碼如下:
1: using System; 2: using System.Collections.Generic; 3: using System.Data.Linq; 4: using System.Data.Linq.Mapping; 5: using System.IO; 6: using System.Linq; 7: using System.Reflection; 8: using System.Text; 9: ? 10: using DongBlog.Common; 11: using DongBlog.Business; 12: using DongBlog.Business.Blogs; 13: ? 14: namespace DongBlog.DataAccess 15: { 16: /// <summary> 17: /// 數據庫 18: /// </summary> 19: public class Database : DataContext, IDatabase 20: { 21: #region Singelton Pattern 22: ? 23: private const string MAPPING_SOURCE_RESOURCE_NAME = "Srims.DataAccess.MappingSource.Xml"; 24: private static MappingSource _MappingSource; 25: private static object _Locker = new object(); 26: ? 27: private Database(string connectionString, MappingSource mappingSource) 28: : base(connectionString, mappingSource) 29: { 30: } 31: ? 32: private static MappingSource getMappingSource() 33: { 34: if (_MappingSource == null) 35: { 36: lock (_Locker) 37: { 38: if (_MappingSource == null) 39: { 40: Stream mapingSourceStream = Assembly.GetAssembly(typeof(Database)) .GetManifestResourceStream(MAPPING_SOURCE_RESOURCE_NAME); 41: if (mapingSourceStream == null) 42: throw new System.IO .InvalidDataException("映射文件不存在!您確定已經將其編譯屬性設置為\"嵌入資源(Embedded Resource)\"?"); 43: _MappingSource = XmlMappingSource.FromStream(mapingSourceStream); 44: } 45: } 46: } 47: return _MappingSource; 48: } 49: ? 50: /// <summary> 51: /// 構造新的數據庫 52: /// </summary> 53: /// <param name="connectionString">數據庫連接字符串</param> 54: /// <returns>數據庫實例</returns> 55: public static Database New(string connectionString) 56: { 57: if (string.IsNullOrEmpty(connectionString)) 58: throw new ArgumentNullException("connectionString"); 59: ? 60: return new Database(connectionString, getMappingSource()); 61: } 62: ? 63: #endregion 64: ? 65: #region IDatabase Members 66: ? 67: /// <summary> 68: /// 取得某一個實體的數據訪問 69: /// </summary> 70: /// <typeparam name="T">實體類型</typeparam> 71: /// <returns>該實體的數據訪問</returns> 72: public IEntityDataAccess<T> GetDataAccess<T>() where T : class 73: { 74: return new EntityDataAccessAdapter<T>(this); 75: } 76: ? 77: /// <summary> 78: /// 提交數據庫變更 79: /// </summary> 80: public void Submit() 81: { 82: base.SubmitChanges(); 83: } 84: ? 85: #endregion 86: ? 87: #region Blogs 88: ? 89: public IEntityDataAccess<Blog> Blogs 90: { 91: get { return new EntityDataAccessAdapter<Blog>(this); } 92: } 93: ? 94: public IEntityDataAccess<BlogClass> BlogClasses 95: { 96: get { return new EntityDataAccessAdapter<BlogClass>(this); } 97: } 98: ? 99: #endregion 100: } 101: }
這個代碼比較長,我們可以把它分為三部分來看,第一部分是實現了一個Singelton模式,用于構造Linq的外部映射文件,涉及的代碼如下:
1: //定義內嵌XML映射資源文件的位置 2: private const string MAPPING_SOURCE_RESOURCE_NAME = "DongBlog.DataAccess.MappingSource.Xml"; 3: //定義XML映射源 4: private static MappingSource _MappingSource; 5: //定義鎖 6: private static object _Locker = new object(); 7: ? 8: //私有的構造函數 9: private Database(string connectionString, MappingSource mappingSource) 10: : base(connectionString, mappingSource) { } 11: ? 12: //構造Linq映射源 13: private static MappingSource getMappingSource() 14: { 15: if (_MappingSource == null) 16: { 17: lock (_Locker) 18: { 19: if (_MappingSource == null) 20: { 21: Stream mapingSourceStream = Assembly.GetAssembly(typeof(Database)) .GetManifestResourceStream(MAPPING_SOURCE_RESOURCE_NAME); 22: if (mapingSourceStream == null) 23: throw new System.IO .InvalidDataException("映射文件不存在!您確定已經將其編譯屬性設置為\"嵌入資源(Embedded Resource)\"?"); 24: _MappingSource = XmlMappingSource.FromStream(mapingSourceStream); 25: } 26: } 27: } 28: return _MappingSource; 29: } 30: ? 31: /// <summary> 32: /// 構造新的數據庫 33: /// </summary> 34: /// <param name="connectionString">數據庫連接字符串</param> 35: /// <returns>數據庫實例</returns> 36: public static Database New(string connectionString) 37: { 38: if (string.IsNullOrEmpty(connectionString)) 39: throw new ArgumentNullException("connectionString"); 40: ? 41: return new Database(connectionString, getMappingSource()); 42: }
以上代碼通過Database的私有構造函數和共有靜態方法保證數據庫使用的外部Linq映射源是靜態唯一的。其中Database構造函數繼承于DataContext的構造函數,該構造函數在Linq中的定義如下:
1: // 2: // Summary: 3: // Initializes a new instance of the System.Data.Linq.DataContext class by referencing 4: // a file source and a mapping source. 5: // 6: // Parameters: 7: // fileOrServerOrConnection: 8: // This argument can be any one of the following:The name of a file where a 9: // SQL Server Express database resides.The name of a server where a database 10: // is present. In this case the provider uses the default database for a user.A 11: // complete connection string. LINQ to SQL just passes the string to the provider 12: // without modification. 13: // 14: // mapping: 15: // The System.Data.Linq.Mapping.MappingSource. 16: public DataContext(string fileOrServerOrConnection, MappingSource mapping);Linq的映射文件使用嵌入式資源的方式儲存(將其文件屬性改為Embedded Resource,如下圖)。而getMappingSource方法通過加鎖的方式使_MappingSource只初始化一次,其中兩次使用了if(_MappingSource ==?null),確保取得鎖的過程中的不會出現并發沖突(盡管這種概率極小)。
?
Database的第二部分是實現IDatabase接口,涉及代碼如下:
1: #region IDatabase Members 2: ? 3: /// <summary> 4: /// 取得某一個實體的數據訪問 5: /// </summary> 6: /// <typeparam name="T">實體類型</typeparam> 7: /// <returns>該實體的數據訪問</returns> 8: public IEntityDataAccess<T> GetDataAccess<T>() where T : class 9: { 10: return new EntityDataAccessAdapter<T>(this); 11: } 12: ? 13: /// <summary> 14: /// 提交數據庫變更 15: /// </summary> 16: public void Submit() 17: { 18: base.SubmitChanges(); 19: } 20: ? 21: #endregion 22: ? 23: #region Blogs 24: ? 25: public IEntityDataAccess<Blog> Blogs 26: { 27: get { return new EntityDataAccessAdapter<Blog>(this); } 28: } 29: ? 30: public IEntityDataAccess<BlogClass> BlogClasses 31: { 32: get { return new EntityDataAccessAdapter<BlogClass>(this); } 33: } 34: ? 35: #endregion?可以從代碼中看到,對于GetDataAccess<T>的調用,全部委托給了EntityDataAccessAdapter類。至于EntityDataAccessAdapter類,全部是調用System.Data.Linq.Table的方法,看一下代碼很容易就可以明白,就不貼出來了。
最后一個問題:Linq的外部映射文件MappingSource.Xml是怎么來的?答案是代碼生成。在DongBlog.Test\Util.cs中新加入以下代碼用于生成MappingSource.Xml。
1: /// <summary> 2: /// 構造Linq的XML映射文件 3: /// </summary> 4: [TestMethod, Description("構造Linq的XML映射文件")] 5: public void Util_CreateXmlMappingFile() 6: { 7: LinqMappingXmlGenerater linqMappingXmlBuilder =new LinqMappingXmlGenerater("", "", Gobal.DatabaseConnectionString); 8: var typeArray = new System.Type[]{ 9: typeof(Blog), 10: typeof(BlogClass), 11: }; 12: linqMappingXmlBuilder.BuildMappingXml(typeArray, Gobal.LingMappingFile); 13: }
這段調用了YD.Data.LinqGenerater.LinqMappingXmlGenerater類用于生成MappingSource.Xml,其實質是使用SqlMetal這個Linq2Sql附帶的工具生成外部映射文件,具體情況可以參看YD\Data\LinqGenerater\LinqMappingXmlGenerater.cs。
至此,我們就有了一個完成的數據訪問層。下一篇我們就進入UI層的開發,看看我們如何把我們前面寫的這些代碼整合在一起。
代碼下載
本文轉自冬冬博客園博客,原文鏈接:http://www.cnblogs.com/yuandong/archive/2008/05/12/1193891.html,如需轉載請自行聯系原作者總結
以上是生活随笔為你收集整理的微型项目实践(8):数据访问的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决github push错误The r
- 下一篇: java后台图片的上传预览接口 I