微型项目实践(8):数据访问的实现

简介:

上一篇文章,我们分析了数据访问是如何定义,以及如何与其它(特别是Business)模块耦合的,今天我们来看一下数据访问(DataAccess)是如何实现的。

system_design

从系统结构图和上一篇“数据访问的定义”中可以知道,数据访问层的任务就是实现IEntityDataAccess和IDatabase接口。由于Linq的出现,我们只需要一个Adapter,将Linq2Sql的类适配到IEntityDataAccess就可以了,其类设计图和文件结构如下如下:

DataAccessDataAccessFile

从图中可以看到,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),确保取得锁的过程中的不会出现并发冲突(尽管这种概率极小)。

LinqXmlFile 

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 ,如需转载请自行联系原作者
相关文章
|
SQL XML Java
程序员都要懂的SQL防注入Mybatis框架SQL防注入
程序员都要懂的SQL防注入Mybatis框架SQL防注入
425 0
Echarts实战案例代码(34):柱状图箭头增长下降
Echarts实战案例代码(34):柱状图箭头增长下降
703 0
|
2月前
|
人工智能 开发框架 监控
AI智能体的开发流程
开发成熟AI智能体是系统工程,需融合自主规划、记忆管理与工具调用。本文详解企业级五阶段标准流程:需求定义、架构设计(LLM/记忆/规划/工具)、核心开发(框架/Prompt/函数调用)、评测优化(黄金数据集/轨迹分析/安全护栏)及LLMOps部署运维。(239字)
|
存储 人工智能 Kubernetes
AI 场景深度优化!K8s 集群 OSSFS 2.0 存储卷全面升级,高效访问 OSS 数据
阿里云对象存储OSS是一款海量、安全、低成本、高可靠的云存储服务,是用户在云上存储的高性价比选择…
|
10月前
|
机器学习/深度学习 人工智能 自然语言处理
大模型
大模型正重塑数字世界,以千亿级参数和深度学习技术驱动AI革命。它赋能内容生成、智能交互与知识服务,同时带来伦理、隐私与能耗挑战。未来需走向高效、可信、向善的可持续发展之路。
|
机器学习/深度学习 自动驾驶 机器人
深度学习之3D场景重建
基于深度学习的3D场景重建是通过深度学习技术从多视角图像或视频数据中重建三维场景结构的过程。它在计算机视觉、增强现实、虚拟现实、机器人导航和自动驾驶等多个领域具有广泛应用。
965 4
|
前端开发
css特效——“凹”和“凸”效果
css特效——“凹”和“凸”效果
612 1
|
机器学习/深度学习 XML 监控
使用A10单卡24G复现DeepSeek R1强化学习过程
使用A10单卡24G复现DeepSeek R1强化学习过程
|
存储 数据处理 Python
Python如何显示对象的某个属性的所有值
本文介绍了如何在Python中使用`getattr`和`hasattr`函数来访问和检查对象的属性。通过这些工具,可以轻松遍历对象列表并提取特定属性的所有值,适用于数据处理和分析任务。示例包括获取对象列表中所有书籍的作者和检查动物对象的名称属性。
387 2
|
开发者 UED 容器
鸿蒙next版开发:ArkTS组件通用属性(图像效果)
在HarmonyOS 5.0中,ArkTS提供了丰富的图像效果属性,如阴影、灰度、高光、饱和度、对比度、图像反转、叠色、色相旋转等,极大丰富了用户界面的表现力。本文详细介绍这些属性并提供示例代码。
530 2