您的位置:首页 > 其它

微型项目实践(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类的代码如下:

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层的开发,看看我们如何把我们前面写的这些代码整合在一起。

代码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐