微型项目实践(8):数据访问的实现
2008-05-12 16:38
513 查看
上一篇文章,我们分析了数据访问是如何定义,以及如何与其它(特别是Business)模块耦合的,今天我们来看一下数据访问(DataAccess)是如何实现的。
从系统结构图和上一篇“数据访问的定义”中可以知道,数据访问层的任务就是实现IEntityDataAccess和IDatabase接口。由于Linq的出现,我们只需要一个Adapter,将Linq2Sql的类适配到IEntityDataAccess就可以了,其类设计图和文件结构如下如下:
从图中可以看到,Database类继承与DataContext,而实现了IDatabase接口;EntityDataAccessAdapter使用System.Data.Linq.Table这个Linq的核心类实现了IEntityDataAccess接口。
Database类的代码如下:
这个代码比较长,我们可以把它分为三部分来看,第一部分是实现了一个Singelton模式,用于构造Linq的外部映射文件,涉及的代码如下:
以上代码通过Database的私有构造函数和共有静态方法保证数据库使用的外部Linq映射源是静态唯一的。其中Database构造函数继承于DataContext的构造函数,该构造函数在Linq中的定义如下:
Linq的映射文件使用嵌入式资源的方式储存(将其文件属性改为EmbeddedResource,如下图)。而getMappingSource方法通过加锁的方式使_MappingSource只初始化一次,其中两次使用了if(_MappingSource==null),确保取得锁的过程中的不会出现并发冲突(尽管这种概率极小)。
Database的第二部分是实现IDatabase接口,涉及代码如下:
可以从代码中看到,对于GetDataAccess<T>的调用,全部委托给了EntityDataAccessAdapter类。至于EntityDataAccessAdapter类,全部是调用System.Data.Linq.Table的方法,看一下代码很容易就可以明白,就不贴出来了。
最后一个问题:Linq的外部映射文件MappingSource.Xml是怎么来的?答案是代码生成。在DongBlog.Test\Util.cs中新加入以下代码用于生成MappingSource.Xml。
这段调用了YD.Data.LinqGenerater.LinqMappingXmlGenerater类用于生成MappingSource.Xml,其实质是使用SqlMetal这个Linq2Sql附带的工具生成外部映射文件,具体情况可以参看YD\Data\LinqGenerater\LinqMappingXmlGenerater.cs。
至此,我们就有了一个完成的数据访问层。下一篇我们就进入UI层的开发,看看我们如何把我们前面写的这些代码整合在一起。
代码下载
从系统结构图和上一篇“数据访问的定义”中可以知道,数据访问层的任务就是实现IEntityDataAccess和IDatabase接口。由于Linq的出现,我们只需要一个Adapter,将Linq2Sql的类适配到IEntityDataAccess就可以了,其类设计图和文件结构如下如下:
从图中可以看到,Database类继承与DataContext,而实现了IDatabase接口;EntityDataAccessAdapter使用System.Data.Linq.Table这个Linq的核心类实现了IEntityDataAccess接口。
Database类的代码如下:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Data.Linq;
usingSystem.Data.Linq.Mapping;
usingSystem.IO;
usingSystem.Linq;
usingSystem.Reflection;
usingSystem.Text;
usingDongBlog.Common;
usingDongBlog.Business;
usingDongBlog.Business.Blogs;
namespaceDongBlog.DataAccess
{
///<summary>
///数据库
///</summary>
publicclassDatabase:DataContext,IDatabase
{
#regionSingeltonPattern
privateconststringMAPPING_SOURCE_RESOURCE_NAME="Srims.DataAccess.MappingSource.Xml";
privatestaticMappingSource_MappingSource;
privatestaticobject_Locker=newobject();
privateDatabase(stringconnectionString,MappingSourcemappingSource)
:base(connectionString,mappingSource)
{
}
privatestaticMappingSourcegetMappingSource()
{
if(_MappingSource==null)
{
lock(_Locker)
{
if(_MappingSource==null)
{
StreammapingSourceStream=Assembly.GetAssembly(typeof(Database))
.GetManifestResourceStream(MAPPING_SOURCE_RESOURCE_NAME);
if(mapingSourceStream==null)
thrownewSystem.IO
.InvalidDataException(
"映射文件不存在!您确定已经将其编译属性设置为\"嵌入资源(EmbeddedResource)\"?");
_MappingSource=XmlMappingSource.FromStream(mapingSourceStream);
}
}
}
return_MappingSource;
}
///<summary>
///构造新的数据库
///</summary>
///<paramname="connectionString">数据库连接字符串</param>
///<returns>数据库实例</returns>
publicstaticDatabaseNew(stringconnectionString)
{
if(string.IsNullOrEmpty(connectionString))
thrownewArgumentNullException("connectionString");
returnnewDatabase(connectionString,getMappingSource());
}
#endregion
#regionIDatabaseMembers
///<summary>
///取得某一个实体的数据访问
///</summary>
///<typeparamname="T">实体类型</typeparam>
///<returns>该实体的数据访问</returns>
publicIEntityDataAccess<T>GetDataAccess<T>()whereT:class
{
returnnewEntityDataAccessAdapter<T>(this);
}
///<summary>
///提交数据库变更
///</summary>
publicvoidSubmit()
{
base.SubmitChanges();
}
#endregion
#regionBlogs
publicIEntityDataAccess<Blog>Blogs
{
get{returnnewEntityDataAccessAdapter<Blog>(this);}
}
publicIEntityDataAccess<BlogClass>BlogClasses
{
get{returnnewEntityDataAccessAdapter<BlogClass>(this);}
}
#endregion
}
}
这个代码比较长,我们可以把它分为三部分来看,第一部分是实现了一个Singelton模式,用于构造Linq的外部映射文件,涉及的代码如下:
//定义内嵌XML映射资源文件的位置
privateconststringMAPPING_SOURCE_RESOURCE_NAME="DongBlog.DataAccess.MappingSource.Xml";
//定义XML映射源
privatestaticMappingSource_MappingSource;
//定义锁
privatestaticobject_Locker=newobject();
//私有的构造函数
privateDatabase(stringconnectionString,MappingSourcemappingSource)
:base(connectionString,mappingSource){}
//构造Linq映射源
privatestaticMappingSourcegetMappingSource()
{
if(_MappingSource==null)
{
lock(_Locker)
{
if(_MappingSource==null)
{
StreammapingSourceStream=Assembly.GetAssembly(typeof(Database))
.GetManifestResourceStream(MAPPING_SOURCE_RESOURCE_NAME);
if(mapingSourceStream==null)
thrownewSystem.IO
.InvalidDataException(
"映射文件不存在!您确定已经将其编译属性设置为\"嵌入资源(EmbeddedResource)\"?");
_MappingSource=XmlMappingSource.FromStream(mapingSourceStream);
}
}
}
return_MappingSource;
}
///<summary>
///构造新的数据库
///</summary>
///<paramname="connectionString">数据库连接字符串</param>
///<returns>数据库实例</returns>
publicstaticDatabaseNew(stringconnectionString)
{
if(string.IsNullOrEmpty(connectionString))
thrownewArgumentNullException("connectionString");
returnnewDatabase(connectionString,getMappingSource());
}
以上代码通过Database的私有构造函数和共有静态方法保证数据库使用的外部Linq映射源是静态唯一的。其中Database构造函数继承于DataContext的构造函数,该构造函数在Linq中的定义如下:
//
//Summary:
//InitializesanewinstanceoftheSystem.Data.Linq.DataContextclassbyreferencing
//afilesourceandamappingsource.
//
//Parameters:
//fileOrServerOrConnection:
//Thisargumentcanbeanyoneofthefollowing:Thenameofafilewherea
//SQLServerExpressdatabaseresides.Thenameofaserverwhereadatabase
//ispresent.Inthiscasetheproviderusesthedefaultdatabaseforauser.A
//completeconnectionstring.LINQtoSQLjustpassesthestringtotheprovider
//withoutmodification.
//
//mapping:
//TheSystem.Data.Linq.Mapping.MappingSource.
publicDataContext(stringfileOrServerOrConnection,MappingSourcemapping);
Linq的映射文件使用嵌入式资源的方式储存(将其文件属性改为EmbeddedResource,如下图)。而getMappingSource方法通过加锁的方式使_MappingSource只初始化一次,其中两次使用了if(_MappingSource==null),确保取得锁的过程中的不会出现并发冲突(尽管这种概率极小)。
Database的第二部分是实现IDatabase接口,涉及代码如下:
#regionIDatabaseMembers
///<summary>
///取得某一个实体的数据访问
///</summary>
///<typeparamname="T">实体类型</typeparam>
///<returns>该实体的数据访问</returns>
publicIEntityDataAccess<T>GetDataAccess<T>()whereT:class
{
returnnewEntityDataAccessAdapter<T>(this);
}
///<summary>
///提交数据库变更
///</summary>
publicvoidSubmit()
{
base.SubmitChanges();
}
#endregion
#regionBlogs
publicIEntityDataAccess<Blog>Blogs
{
get{returnnewEntityDataAccessAdapter<Blog>(this);}
}
publicIEntityDataAccess<BlogClass>BlogClasses
{
get{returnnewEntityDataAccessAdapter<BlogClass>(this);}
}
#endregion
可以从代码中看到,对于GetDataAccess<T>的调用,全部委托给了EntityDataAccessAdapter类。至于EntityDataAccessAdapter类,全部是调用System.Data.Linq.Table的方法,看一下代码很容易就可以明白,就不贴出来了。
最后一个问题:Linq的外部映射文件MappingSource.Xml是怎么来的?答案是代码生成。在DongBlog.Test\Util.cs中新加入以下代码用于生成MappingSource.Xml。
///<summary>
///构造Linq的XML映射文件
///</summary>
[TestMethod,Description("构造Linq的XML映射文件")]
publicvoidUtil_CreateXmlMappingFile()
{
LinqMappingXmlGeneraterlinqMappingXmlBuilder=
newLinqMappingXmlGenerater("","",Gobal.DatabaseConnectionString);
vartypeArray=newSystem.Type[]{
typeof(Blog),
typeof(BlogClass),
};
linqMappingXmlBuilder.BuildMappingXml(typeArray,Gobal.LingMappingFile);
}
这段调用了YD.Data.LinqGenerater.LinqMappingXmlGenerater类用于生成MappingSource.Xml,其实质是使用SqlMetal这个Linq2Sql附带的工具生成外部映射文件,具体情况可以参看YD\Data\LinqGenerater\LinqMappingXmlGenerater.cs。
至此,我们就有了一个完成的数据访问层。下一篇我们就进入UI层的开发,看看我们如何把我们前面写的这些代码整合在一起。
相关文章推荐
- 微型项目实践(7):数据访问的定义
- 微型项目实践(9):页面的数据访问策略
- 微型项目实践(7):数据访问的定义
- Asp.Net大型项目实践(4)-用NHibernate保存和查询我们的业务领域对象之实现基本的数据库访问(附源码)
- 项目中遇到通过使用路由策略实现主从数据库访问数据不同步的问题
- NHibernate+WCF项目实战(二)使用NHibernate实现数据访问并进行单元测试
- Asp.Net大型项目实践(4)-用NHibernate保存和查询我们的业务领域对象之实现基本的数据库访问(附源码)
- NHibernate+WCF项目实战(二)使用NHibernate实现数据访问并进行单元测试
- Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问
- Vue项目数据动态过滤实践及实现思路
- 水果项目第2集-建立数据库->编写数据访问基础类->实现类的方法->调试通过
- 在部署项目时实现自动安装FrameWork及数据访问部件
- 在部署项目时实现自动安装FrameWork及数据访问部件
- 【java】itoo项目实战之百万数据查询优化收集与实践
- 微型项目实践(6):Business层代码分析——实体类的生成策略
- 微型项目实践(4):Common层代码分析
- 第六周上机实践项目6-复数模板类(3、友元的实现)
- web项目实现Excel数据导入导出
- 多样化实现Windows phone 7本地数据访问<5>——深入Rapid Repository
- java Web项目实践之7 添加功能、精确查询功能的设计及实现