注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

天涯倦客的博客

祝福你朋友永远快乐!

 
 
 

日志

 
 

.net中的数据访问(介绍)  

2013-01-05 18:03:42|  分类: asp.net |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

介绍.NET中不同的数据访问层的使用方式,由此得出Entity Framework在一个.NET系统中的应用及其在原有设计基础上的改变。从大的方面来看数据访问的设计方案基本有如下几类:

  ? DataSet
  ? 手写代码通过ADO.NET2.0连接类与数据库交互
  ? ORM组件


(1)DataSet方案
最基本的Dataset数据访问的实现使用下图表示:

如图所示,DataSet与数据源之间通过DataAdapter连接,逻辑中直接访问DataSet获取数据,或是通过ADO.NET2.0的非连接类,或者通过强类型DataSet以一种类型安全的方式访问数据。
缺点:逻辑代码与数据访问代码耦合高。


改进的的DataSet方案

这种设计方式将业务所需的实体抽象出来,并把对DataSet的操作封装在其中,这样一定程序上解除业务逻辑与数据访问的耦合。


(2)手写代码通过ADO.NET2.0连接类与数据库交互
这种方式是我使用的最多的一种方式,其可以提供最大的控制能力,且效率最高,唯一的不足是当业务变化时修改数据访问代码的工作量比较大,通过代码生成器也能一定程度上解决这个问题。


(3)ORM组件

ORM–LINQtoSQL
在.NET平台下ORM的解决方案有不少,本文只讨论两个微软官方的解决方案。先是LINQtoSQL技术。
LINQtoSQL是一个将不再更新的技术。其有很多不足之处,如,不能灵活的定义对象模型与数据表之间的映射、无法扩展提供程序只能支持SQLServer等。
这样数据访问层的设计如下所示:

ORM–ADO.NETEntityFramework
作为下一代数据访问的技术领导者。EntityFramework的设计很多地方都保留了高扩展性。其最重要的一个改进在于其映射定义的灵活性。先来看下图:

由图可以看出,使用EntityFramework可以充分的定义与数据库表映射的实体,并将这个实体直接用于业务逻辑层或作为服务的数据契约。

实体设计较其他技术的优势体现在以下几方面:
  ? 创建ComplexType
  ? EntitySet的继承
使用Entity Framework后,可以将实体类的设计工作完全放在EDM的设计过程中,而不再需要手工写一些大同小异的代码,并且对这个实体模型(包含于EDM中)可以在运行时修改并生效。另外,开发人员与数据库直接打交道的次数将大大减少,大部分时间开发人员只需操作实体模型,框架会自动完成对数据库的操作。

上图展现了访问数据的实体框架体系结构

(二)Entity Framework的核心--EDM(Entity Data Model)

EDM(实体数据模型)由以下三种模型和具有相应文件扩展名的映射文件进行定义。


概念架构定义语言文件 (.csdl) -- 定义概念模型。
存储架构定义语言文件 (.ssdl) -- 定义存储模型(又称逻辑模型)。
映射规范语言文件 (.msl) -- 定义存储模型与概念模型之间的映射。

这三部分在一起就是EDM模式。EDM模式在项目中的表现形式就是扩展名为.edmx的文件。这个包含EDM的文件可以使用VisualStudio中的EDM设计器来设计。由于这个文件本质是一个xml文件,可以手工编辑此文件来自定义CSDL、MSL与SSDL这三部分。下面详细分析一下这个xml文件及三个其重要组成部分。

首先介绍如何在VS中创建EDM

(1)创建一个项目(在这里我创建的是ASP.NET MVC 3 WEB 应用程序)

(2)右键“Models”--“添加项目”--“ADO.NET Entity Data Model”项目(然后按照向导添加)

最终结果如图:

右击红色框中的MoviesDBModel.edmx文件 选择“打开方式”--“XML(文件)编辑器”打开

这个文件展示了示例项目完整的EDM文件的XML形式:

第一行表明这是一个xml文件。
<?xmlversion="1.0"encoding="utf-8"?>
以下这一行是EDM的根节点,定义了一个表明版本的属性及这个EDM使用的命名空间:
<edmx:EdmxVersion="1.0"xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
接下来由注释可以看到EDM被分为两部分,第一部分是EDM的核心,第二部分用于实体设计器(这一部分不研究)。

第一部分中节点<edmx:Runtime>下定义了以下三部分:

EDM之CSDL
CSDL定义了EDM或者说是整个程序的灵魂部分–概念模型。当前流行的软件设计方法通常都是由设计其概念模型起步。说概念模型可能比较抽象一个更容易接受的名字就是实体类。实体类是面向对象设计中一个最根本的组成部分,其体现了现实世界中对象作为一种计算中可以表示的对象设计方法。而EDM的CSDL就是要达到这样一个目的。这个在下文介绍EntityFramework优点时另有说明。
这个文件完全以程序语言的角度来定义模型的概念。即其中定义的实体、主键、属性、关联等都是对应于.NET Framework中的类型。

下面xmlelement来自作业提交系统(有删节):
<!--CSDLcontent-->
<edmx:ConceptualModels>
<SchemaNamespace="ASSModel"Alias="Self"xmlns=http://schemas.microsoft.com/ado/2006/04/edm>
<EntityContainerName="ASSEntities">
<FunctionImport Name="GETHOUSEWORKDONE"EntitySet="UpAssignments"ReturnType="Collection(Self.UpAssignments)">
<ParameterName="StuID"Type="Int32"Mode="In"/>
<ParameterName="ClassID"Type="Int32"Mode="In"/>
<ParameterName="Semester"Type="String"Mode="In"/>
</FunctionImport>
<!--以上删节–5个存储过程-->
<EntitySetName="Assignments"EntityType="ASSModel.Assignments"/>
<EntitySetName="Classes"EntityType="ASSModel.Classes"/>
<EntitySetName="Courses"EntityType="ASSModel.Courses"/>
<EntitySetName="SetCourses"EntityType="ASSModel.SetCourses"/>
<EntitySetName="Students"EntityType="ASSModel.Students"/>
<EntitySetName="Teachers"EntityType="ASSModel.Teachers"/>
<EntitySetName="UpAssignments"EntityType="ASSModel.UpAssignments"/>
<AssociationSet Name="FK_SetCourses_Classes"Association="ASSModel.FK_SetCourses_Classes">
<EndRole="Classes"EntitySet="Classes"/>
<EndRole="SetCourses"EntitySet="SetCourses"/>
</AssociationSet>
<!--以上删节–6个关系集-->
</EntityContainer>
<!--以下保留一个EntityType作为示例-->
<EntityType Name="Students">
<Key>
<PropertyRefName="StuID"/>
</Key>
<PropertyName="StuID"Type="Int32"Nullable="false"/>
<PropertyName="StuName"Type="String"Nullable="false"MaxLength="10"Unicode="true"FixedLength="true"/>
<PropertyName="Pswd"Type="String"Nullable="false"MaxLength="50"Unicode="false"FixedLength="true"/>
<NavigationProperty Name="Classes"Relationship="ASSModel.FK_Students_Classes"FromRole="Students"ToRole="Classes"/>
<NavigationProperty Name="UpAssignments"Relationship="ASSModel.FK_UpAssignments_Students"FromRole="Students"ToRole="UpAssignments"/>
</EntityType>
<!--仅保留与上文AssociationSet对应的Association-->
<AssociationName="FK_SetCourses_Classes">
<EndRole="Classes"Type="ASSModel.Classes"Multiplicity="1"/>
<EndRole="SetCourses"Type="ASSModel.SetCourses"Multiplicity="*"/>
</Association>
</Schema>
</edmx:ConceptualModels>
这部分XML文档,Schema是CSDL的根元素,其中定义的Namespace是用于ObjectContext与EntityClass的命名空间,Alias-别名为此命名空间Namespace指定一个易记的名称,在定义Alias之后,在此Schema内的Element均可以该Alias作为Namespace的别名。Alias的使用可以参考如下xml element:
<FunctionImport Name="GETHOUSEWORKDONE"EntitySet="UpAssignments"ReturnType="Collection(Self.UpAssignments)">
在这个根元素的内部的文档结构第一部分–实体容器大致如下:
<EntityContainer/>
<FunctionImport />
<EntitySet/>
<AssociationSet />
</EntityContainer>
下面的表格说明了这些节点及其属性的作用


可以看出,Entity与Assciation都被分开定义与两个部分,这样设计是出于当有多个EntityContainer时,其中的EntitySet或AssociationSet可以共享Entity或Association的定义。
接下来看一下CSDL中最后一部分,Entity与Association的定义。
首先是Entity:
<EntityType Name="Students">
<Key>
<PropertyRefName="StuID"/>
</Key>
<PropertyName="StuID"Type="Int32"Nullable="false"/>
<PropertyName="StuName"Type="String"Nullable="false"MaxLength="10"Unicode="true"FixedLength="true"/>
<PropertyName="Pswd"Type="String"Nullable="false"MaxLength="50"Unicode="false"FixedLength="true"/>
<NavigationProperty Name="Classes"Relationship="ASSModel.FK_Students_Classes"FromRole="Students"ToRole="Classes"/>
<NavigationProperty Name="UpAssignments"Relationship="ASSModel.FK_UpAssignments_Students"FromRole="Students"ToRole="UpAssignments"/>
</EntityType>
下表说明了其属性及其子节点与子节点的属性的含义:


最后Association节,这是真正定义关系的地方。首先看示例:
<!--仅保留与上文AssociationSet对应的Association-->
<AssociationName="FK_SetCourses_Classes">
<EndRole="Classes"Type="ASSModel.Classes"Multiplicity="1"/>
<EndRole="SetCourses"Type="ASSModel.SetCourses"Multiplicity="*"/>
</Association>
这一节符合以下结构:
<Association>
<End/>
<ReferentialConstraint>
<Principal>
<PropertyRef/>
</Principal>
<Dependent>
<PropertyRef/>
</Dependent>
</ReferentialConstraint>
</Association>
属性及其子元素属性的说明:


EDM之SSDL
这个文件中描述了表、列、关系、主键及索引等数据库中存在的概念。

<!--SSDLcontent-->
<edmx:StorageModels>
<SchemaNamespace="ASSModel.Store"Alias="Self"Provider="System.Data.SqlClient"ProviderManifestToken="2008"xmlns:store="http://schemas.microsoft.com/ado/2007/12/ed
m/EntityStoreSchemaGenerator"xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl">
<EntityContainerName="ASSModelStoreContainer">
<EntitySetName="Assignments"EntityType="ASSModel.Store.Assignments"store:Type="T
ables"Schema="dbo"/>
<!--省略7个EntitySet的定义-->
</EntityContainer>
<!--以下省略7个EntityType的定义-->
<EntityType Name="Assignments">
<Key>
<PropertyRefName="AssID"/>
</Key>
<PropertyName="AssID"Type="int"Nullable="false"StoreGeneratedPattern="Identity"/>
<PropertyName="AssName"Type="nchar"Nullable="false"MaxLength="20"/>
<PropertyName="AssDes"Type="nvarchar"MaxLength="500"/>
<PropertyName="SCID"Type="int"Nullable="false"/>
<PropertyName="Deadline"Type="datetime"Nullable="false"/>
<PropertyName="QuesFileName"Type="nvarchar"MaxLength="500"/>
<PropertyName="QuesFileUrl"Type="nvarchar"Nullable="false"MaxLength="500"/>
</EntityType>
<!--保留与CSDL中对应的Function-->
<FunctionName="GETHOUSEWORKDONE"Aggregate="false"BuiltIn="false"NiladicFunction="false"IsComposable="false"ParameterTypeSemantics="AllowImplicitConversion"Sche
ma="dbo">
<ParameterName="StuID"Type="int"Mode="In"/>
<ParameterName="ClassID"Type="int"Mode="In"/>
<ParameterName="Semester"Type="varchar"Mode="In"/>
</Function>
</Schema>
</edmx:StorageModels>
看文档的结构,SSDL与CSDL很详细,只是其中EntityType等使用数据库的概念的描述。
这其中有一个需要稍微介绍节点,DefiningQuery,首先看一下其出现的位置:


DefiningQuery定义通过实体数据模型(EDM) 内的客户端投影映射到数据存储视图的查询。此类映射是只读的。也就是说如果想要更新此类EntitySet,需要使用下文介绍存储过程时提到的定义更新实体的存储过程的方法,使用定义的存储过程来更新这样的EntitySet。当在实体类设计器中导入无主键的表时,会自动生成此类使用DefiningQuery定义的EntitySet,要式样EntityFramework提供的自动更新服务而不定义存储过程,需要给数据表添加一个适当的主键,删除DefiningQuery节点并更新数据模型。


EDM之MSL
这个文件即上面所述的CSDL与SSDL的对应,主要包括CSDL中属性与SSDL中列的对应。
<!--C-Smappingcontent-->
<edmx:Mappings>
<MappingSpace="C-S"xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS">
<EntityContainerMapping StorageEntityContainer="ASSModelStoreContainer"CdmEntityContainer="ASSEntities">
<EntitySetMappingName="Assignments">
<EntityTypeMappingTypeName="IsTypeOf(ASSModel.Assignments)">
<MappingFragmentStoreEntitySet="Assignments">
<ScalarProperty Name="QuesFileName"ColumnName="QuesFileName"/>
<ScalarProperty Name="AssDes"ColumnName="AssDes"/>
<ScalarProperty Name="AssID"ColumnName="AssID"/>
<ScalarProperty Name="AssName"ColumnName="AssName"/>
<ScalarProperty Name="Deadline"ColumnName="Deadline"/>
<ScalarProperty Name="QuesFileUrl"ColumnName="QuesFileUrl"/>
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<!--省略EntitySetMapping若干-->
<!--保留对应于CSDL与SSDL的FunctionImportMapping-->
<FunctionImportMappingFunctionImportName="GETHOUSEWORKDONE"FunctionName="ASSModel.Store.GETHOUSEWORKDONE"/>
<AssociationSetMappingName="FK_UpAssignments_Assignments"TypeName="ASSModel.FK_UpAssignments_Assignments"StoreEntitySet="UpAssignments">
<EndPropertyName="Assignments">
<ScalarProperty Name="AssID"ColumnName="AssID"/>
</EndProperty>
<EndPropertyName="UpAssignments">
<ScalarProperty Name="UpAssID"ColumnName="UpAssID"/>
</EndProperty>
</AssociationSetMapping>
<!--省略AssociationSetMapping若干-->
</EntityContainerMapping>
</Mapping>
</edmx:Mappings>
如上代码所示,MSL的根节点为Mapping,其中可以包含多个EntityContainerMapping(上例只有一个),每一个EntityContainerMapping对应着两个分别来自CSDL与SSDL的EntityContainer。这个EntityContainerMapping就是描述这两个EntityContainer间的对应。下面再给出一段代码展示EntityContainerMapping的基本格式。
<EntityContainerMapping StorageEntityContainer=""CdmEntityContainer="">
<EntitySetMapping>
<EntityTypeMapping>
<MappingFragment>
<ScalarProperty />
</MappingFragment>
<ModificationFunctionMapping>
<InsertFunction />
<DeleteFunction />
<UpdateFunction />
</ModificationFunctionMapping>
</EntityTypeMapping>
</EntitySetMapping>
<AssociationSetMapping>
<EndProperty>
<ScalarProperty />
</EndProperty>
</AssociationSetMapping>
<FunctionImportMapping/>
</EntityContainerMapping>
同上文,下面列出这些节点的属性


说明1:以上表中很重要的一个属性是MappingFragment中的StoreEntitySet属性,就像这个属性的说明中所说,其描述了CSDL的Entity对应到的SSDL的Entity的名称。这是实现下文EDM映射方案中第二条将一个概念模型的实体映射到多个存储模型的实体的关键设置。
说明2:Contain这个元素及其属性的作用是,当多个概念模型实体映射到一个存储模型实体时,该元素的属性决定了在什么情况下一个概念模型实体映射到指定的存储模型实体。
说明3:QueryView元素定义概念模型中的实体与存储模型中的实体之间的只读映射。使用根据存储模型计算的EntitySQL查询定义此查询视图映射,并以概念模型中的实体表达结果集。同DefiningQuery定义的查询。此映射也是只读的。就是说如果想要更新此类EntitySet,也需要使用下文介绍存储过程时提到的定义更新实体的存储过程的方法,使用定义的存储过程来更新这样的EntitySet。当多对多关联在存储模型中所映射到的实体表示关系架构中的链接表时,必须为此链接表在AssociationSetMapping元素中定义一个QueryView元素。定义查询视图时,不能在AssociactionSetMapping元素上指定StorageSetName属性。定义查询视图时,AssociationSetMapping元素不能同时包含EndProperty映射。

  评论这张
 
阅读(705)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017