前面的文章讨论了使用SQL语句和存储过程两种数据访问层的实现方式,这一篇里,将讨论使用ORM方式实现数据访问层的方法。
对象-关系映射(Object/Relation Mapping,简称ORM),是随着面向对象的软件开发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
目前.NET平台上有许多ORM框架可供选择,如NBear、NHibernate等等。这里我们选择NBear实现ORM。
NBear是由博客园的Teddy's Knowledge Base团队开发的一个开源框架,主要用来提高.NET平台的开发效率,其中包含了ORM、IoC、MVP等多个组件,这里仅仅用到其中的ORM功能。关于NBear的详细使用方法本文不再详述,请参考NBear入门教程。NBear的最新版本下载地址为/hjf1223/NBearV3.7.2.11_src.rar。
下面我们一步一步实现数据访问层的ORM实现。
1.创建实体设计工程
使用NBear实现ORM功能,首先要创建一个实体设计工程,这个工程最终不会应用到系统中,但是必须通过它来生成NBear实体类以及配置文件。
首先,我们在解决方案下新建一个工程,名字为NBearEntityDesign,并为这个工程添加到文件mon.Design.dll的引用,这个文件在NBear文件包的dist目录下。
完成后,在这个工程下新建一个C#文件,名为EntityDesign.cs,这个文件就是设计文件,根据对实体和数据库的设计,编写完整代码如下:
EntityDesign.cs
2using System.Collections.Generic; 3using System.Text; 4using mon.Design; 5 6namespace NGuestBook.NBearEntityDesign 7{ 8public interface TAdmin : Entity 9{ 10[PrimaryKey] 11int ID { get; } 12[SqlType("nvarchar(20)")] 13string Name { get; set; } 14[SqlType("nvarchar(50)")] 15string Password { get; set; } 16} 17 18public interface TComment : Entity 19{ 20[PrimaryKey] 21int ID { get; } 22[SqlType("ntext")] 23string Content { get; set; } 24DateTime Time { get; set; } 25int MessageID { get; set; } 26} 27 28public interface TMessage : Entity 29{ 30[PrimaryKey] 31int ID { get; } 32[SqlType("nvarchar(20)")] 33string GuestName { get; set; } 34[SqlType("nvarchar(100)")] 35string GuestEmail { get; set; } 36[SqlType("ntext")] 37string Content { get; set; } 38DateTime Time { get; set; } 39[SqlType("ntext")] 40string Reply { get; set; } 41[SqlType("nvarchar(10)")] 42string IsPass { get; set; } 43} 44}1using System;
设计完后,将这个工程编译备用。 2.创建NBear专用实体类及配置文件 在NBear文件包的dist目录下,有一个NBear.Tools.EntityDesignToEntity.exe程序,打开它,点击“Browse”按钮,选择刚才编译生成的NGuestBook.NBearEntityDesign.dll文件,并在Output Namespace文本框里输入相应的命名空间,这里我们应输入“NGuestBook.NBearDAL”。然后点击“Generate Entities”按钮,这时会在底下的文本框里生成NBear专用实体类代码。 在解决方案下新建一个工程NBearDAL,用于存放所有ORM数据访问层的实现代码。在这个工程下新建Entities.cs,将刚才自动生成的代码覆盖掉这个文件的代码,专用实体类就做好了。 另外,需要给工程NBearDAL添加到mon.dll和NBear.Data.dll的引用,这两个文件都在dist目录下。 点击“Generate Configuration”按钮,这时会生成配置代码。在Web工程下新建文件NBearConfig.xml,将生成的代码复制到这个文件里保存。 最后还要修改一下Web.config文件。增加如下配置代码: <section name="entityConfig" type="mon.EntityConfigurationSection, mon"/> </configSections> <entityConfig> <includes> <add key="Sample Entity Config" value="~/NBearConfig.xml"/> </includes> </entityConfig> 然后再在<connectionStrings>节点下增加如下项: 其中connectionString是连接字符串,根据个人不同情况进行修改。这里使用的是SQLServer。 因为数据库在上一篇中已经创建好了,这里就不需要创建数据库了。 3.编写转换器 这里出现了一个矛盾:业务逻辑层和表示层需要使用通用的实体类,如AdminInfo,而NBear需要使用专用实体类。怎么解决这个矛盾呢?我这里使用的方法是一个我称之为“转换器”的方法。 即为没一个实体写一个专门的转换器,实现两种实体类的转换。这里以管理员实体为例,这个转换器写在NBearDAL工程下的AdminConvertor.cs文件中。具体代码如下: AdminConvertor 2using NGuestBook.Entity; 3 4namespace NGuestBook.NBearDAL 5{ 6/** <summary> 7/// 实体类转换器-管理员 8/// </summary> 9public sealed class AdminConvertor 10{ 11/** <summary> 12/// 由普通管理员实体类转化为NBear专用管理员实体类 13/// </summary> 14/// <param name="commonEntity">普通实体类</param> 15/// <returns>NBear专用实体类</returns> 16public static TAdmin CommonEntityToNBearEntity(AdminInfo commonEntity) 17{ 18TAdmin nbaerEntity = new TAdmin(); 19nbaerEntity.ID = commonEntity.ID; 20nbaerEntity.Name = commonEntity.Name; 21nbaerEntity.Password = commonEntity.Password; 22 23return nbaerEntity; 24} 25 26/** <summary> 27/// 由NBear专用管理员实体类转化为普通管理员实体类 28/// </summary> 29/// <param name="nbearEntity">NBear专用实体类</param> 30/// <returns>普通实体类</returns> 31public static AdminInfo NBearEntityToCommonEntity(TAdmin nbearEntity) 32{ 33AdminInfo commonEntity = new AdminInfo(); 34commonEntity.ID = nbearEntity.ID; 35commonEntity.Name = nbearEntity.Name; 36commonEntity.Password = nbearEntity.Password; 37 38return commonEntity; 39} 40} 41} 4.实现数据访问层 做完上述工作,我们就可以来实现数据访问层了。借助于NBear框架的支持,我们可以非常方便的使用ORM方式访问数据库。关于NBear的细节,这里不再赘述,以管理员为例,具体代码如下: AdminDAL.cs 2using System.Collections.Generic; 3using System.Text; 4using mon; 5using NGuestBook.IDAL; 6using NGuestBook.Entity; 7using mon; 8using NBear.Data; 9 10namespace NGuestBook.NBearDAL 11{ 12public class AdminDAL : IAdminDAL 13{ 14/** <summary> 15/// 插入管理员 16/// </summary> 17/// <param name="admin">管理员实体类</param> 18/// <returns>是否成功</returns> 19public bool Insert(AdminInfo admin) 20{ 21Gateway.SetDefaultDatabase("NBearConnectionString"); 22DbTransaction transcation = Gateway.Default.BeginTransaction(); 23try 24{ 25Gateway.Default.Save<TAdmin>(monEntityToNBearEntity(admin)); 26mit(); 27return true; 28} 29catch 30{ 31transcation.Rollback(); 32return false; 33} 34finally 35{ 36Gateway.Default.CloseTransaction(transcation); 37} 38} 39 40/** <summary> 41/// 删除管理员 42/// </summary> 43/// <param name="id">欲删除的管理员的ID</param> 44/// <returns>是否成功</returns> 45public bool Delete(int id) 46{ 47Gateway.SetDefaultDatabase("NBearConnectionString"); 48DbTransaction transcation = Gateway.Default.BeginTransaction(); 49try 50{ 51Gateway.Default.Delete<TAdmin>(id); 52mit(); 53return true; 54} 55catch 56{ 57transcation.Rollback(); 58return false; 59} 60finally 61{ 62Gateway.Default.CloseTransaction(transcation); 63} 64} 65 66/** <summary> 67/// 更新管理员信息 68/// </summary> 69/// <param name="admin">管理员实体类</param> 70/// <returns>是否成功</returns> 71public bool Update(AdminInfo admin) 72{ 73Gateway.SetDefaultDatabase("NBearConnectionString"); 74DbTransaction transcation = Gateway.Default.BeginTransaction(); 75PropertyItem[] properties = { 76new PropertyItem("Name"), 77new PropertyItem("Password") 78}; 79object[] values ={ 80admin.Name, 81admin.Password 82}; 83try 84{ 85Gateway.Default.Update<TAdmin>(properties, values, null, transcation); 86mit(); 87return true; 88} 89catch 90{ 91transcation.Rollback(); 92return false; 93} 94finally 95{ 96Gateway.Default.CloseTransaction(transcation); 97} 98} 99 100/** <summary> 101/// 按ID取得管理员信息 102/// </summary> 103/// <param name="id">管理员ID</param> 104/// <returns>管理员实体类</returns> 105public AdminInfo GetByID(int id) 106{ 107Gateway.SetDefaultDatabase("NBearConnectionString"); 108TAdmin tAdmin = Gateway.Default.Find<TAdmin>(TAdmin._.ID == id); 109return tAdmin == null ? null : AdminConvertor.NBearEntityToCommonEntity(tAdmin); 110} 111 112/** <summary> 113/// 按用户名及密码取得管理员信息 114/// </summary> 115/// <param name="name">用户名</param> 116/// <param name="password">密码</param> 117/// <returns>管理员实体类,不存在时返回null</returns> 118public AdminInfo GetByNameAndPassword(string name, string password) 119{ 120Gateway.SetDefaultDatabase("NBearConnectionString"); 121TAdmin tAdmin = Gateway.Default.Find<TAdmin>(TAdmin._.Name == name && TAdmin._.Password == password); 122return tAdmin == null ? null : AdminConvertor.NBearEntityToCommonEntity(tAdmin); 123} 124 125/** <summary> 126/// 按管理员名取得管理员信息 127/// </summary> 128/// <param name="name">管理员名</param> 129/// <returns>管理员实体类</returns> 130public AdminInfo GetByName(string name) 131{ 132Gateway.SetDefaultDatabase("NBearConnectionString"); 133TAdmin tAdmin = Gateway.Default.Find<TAdmin>(TAdmin._.Name == name); 134return tAdmin == null ? null : AdminConvertor.NBearEntityToCommonEntity(tAdmin); 135} 136 137/** <summary> 138/// 取得全部管理员信息 139/// </summary> 140/// <returns>管理员实体类集合</returns> 141public IList<AdminInfo> GetAll() 142{ 143IList<AdminInfo> adminCollection = new List<AdminInfo>(); 144Gateway.SetDefaultDatabase("NBearConnectionString"); 145TAdmin[] tAdminCollection = Gateway.Default.FindArray<TAdmin>(null, TAdmin._.ID.Desc); 146foreach (TAdmin tAdmin in tAdminCollection) 147{ 148adminCollection.Add(AdminConvertor.NBearEntityToCommonEntity(tAdmin)); 149} 150return adminCollection; 151} 152} 153}<configSections>
<add name="NBearConnectionString" connectionString="Server=LOCALHOSTSQLEXPRESS;Database=NGuestBook;Uid=WebUser;Pwd=123456" providerName="NBear.Data.SqlServer.SqlDbProvider"/>
1using System;
1using System;