Spring.NET 1.3.2 集成 NHibernate 3.2 - 4 - 实现基本的数据访问
转眼一个星期过去了,还没有实际访问数据库,要加油了。
万丈高楼从地起,我们一步一步开始。
一. 准备数据
数据访问自然又要数据了,这里我们使用 《Microsoft SQL Server 2008技术内幕:T-SQL语言基础 》 一书中的示例数据库,这本书的详细介绍可以在这里找到。
非常好的一本书,其中的一些内容在别的地方是找不到的,比如查询的处理过程以及对 SQL Server 中锁的介绍等等,不幸的是书中提供的示例代码地址被墙了,我在博客园中上传了一份。
下载地址:https://files.cnblogs.com/haogj/TSQLFundamentals2008.rar
你必须已经安装了 SQL Server 2008,各种版本都可以,在查询分析器窗口中,直接执行下载的脚本,就可以完成数据库的创建了。完成之后的数据库如图所示。
下面我们将要访问其中的 Sales.Customers 表,这个表的结构如下:
二. 创建解决方案
打开 Visual Studio 2010, 创建一个新的网站项目。
1. 创建实体项目
在解决方案中,添加一个新的类库项目,这里命名为 Forbetter.Domain。
删除模板中自动添加的 Class1.cs, 在其中添加一个类文件 Customer.cs,修改其中的代码为如下内容。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Forbetter.Domain { public class Customer { public virtual int Id { get; private set; } public virtual string CompanyName { get; set; } public virtual string ContactName { get; set; } public virtual string ContactTitle { get; set; } public virtual string Address { get; set; } public virtual string City { get; set; } public virtual string Region { get; set; } public virtual string PostalCode { get; set; } public virtual string Country { get; set; } public virtual string Phone { get; set; } public virtual string Fax { get; set; } } }
以后,我们对数据库中 Customer 表的访问将通过这个类进行。
需要注意的是,其中的属性都使用 virtual 进行了修饰。这是 NHibernate 的要求。
为了表达这个类与关系之间的映射关系,在 NHibernate 中需要定义对象关系映射,映射的方式有多种,最常见的是使用 xml 配置文件。
在项目中增加一个名为 Customer.hbm.xml 的 xml 文件,这个文件的扩展名必须为 hbm.xml。以后, NHibernate 可以自动寻找这种扩展名的文件来寻找映射关系。
在属性窗口中,将这个文件的生成操作设置为:嵌入的资源,这样这个文件将会被编译器嵌入到生成的 dll 文件中。
这个文件的内容如下:
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Forbetter.Domain"> <class name="Forbetter.Domain.Customer" table="Sales.Customers" lazy="false" > <id name="Id" unsaved-value="null" column="custid" type="int" > <generator class="identity" /> </id> <property name="CompanyName" column="CompanyName" length="40" not-null="true" index="CompanyName"/> <property name="ContactName" length="30" not-null="false"/> <property name="ContactTitle" length="30" not-null="false"/> <property name="Address" length="60" not-null="false"/> <property name="City" length="15" not-null="false" index="City"/> <property name="Region" length="15" not-null="false" index="Region"/> <property name="PostalCode" length="10" not-null="false" index="PostalCode"/> <property name="Country" type="String" length="15" not-null="false"/> <property name="Phone" length="24" not-null="false"/> <property name="Fax" length="24" not-null="false"/> </class> </hibernate-mapping>
现在,这个项目的内容应该如下。
2. 创建数据访问项目
在解决方案中添加第三个项目,
项目中需要添加对 Forbetter.Domain 的引用。
这里开始使用 NHibernate 了,为项目添加 NHibernate 的引用。这里涉及到两个程序集:NHibernate.dll 和 Iesi.Collectionss.dll,在项目中还使用了 Spring.NET 的特性,所以还需要添加对 Spring.Core.dll 的引用。
总共会有四个程序集的引用。
在这个项目中添加一个文件夹 Config,然后,在其中增加一个 xml 文件,命名为 dataAccess.xml。这个文件的生成属性,也需要定义为嵌入的资源,其中的内容如下:
<?xml version="1.0" ?> <objects xmlns="http://www.springframework.net" xmlns:db="http://www.springframework.net/database" xmlns:tx="http://www.springframework.net/tx" > <!--描述--> <description> 数据访问的配置信息 包括:DbProvider NHibernate </description> <!-- 通过主应用程序的上下文配置文件引用 --> <object type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core"> <property name="ConfigSections" value="spring/databaseSettings"/> </object> <!-- 数据库的配置 --> <db:provider id="DbProvider" provider="SqlServer-2.0" connectionString="Data Source=${db.server};Database=${db.database};Integrated Security=true;" /> <!-- NHibernate 配置 --> <!-- 可以通过 name 为其指定别名 name="SessionFactory" --> <object id="NHibernateSessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject,Spring.Data.NHibernate32" > <!-- 关于数据库连接的配置,直接使用 DbProvider 中的设置,这样,不需要为 Hibernate 再提供连接串和驱动 --> <property name="DbProvider" ref="DbProvider"/> <!-- 包含有映射文件的程序集,需要分析的hbm程序集名称 --> <property name="MappingAssemblies"> <list> <value>Forbetter.Domain</value> </list> </property> <!-- 其他的参数 --> <property name="HibernateProperties"> <dictionary> <!-- 方言 --> <entry key="dialect" value="NHibernate.Dialect.MsSql2008Dialect"/> <entry key="use_proxy_validator" value="false" /> <entry key="show_sql" value="true"/> </dictionary> </property> <!-- 必须增加此项说明,与 Spring 的声明式事务集成 --> <property name="ExposeTransactionAwareSessionFactory" value="true" /> </object> </objects>
这里需要的注意的是,在数据库连接串中,使用了类似 ${db.server} 的方式,这里的 db.server 是定义在配置文件中变量名,我们将会在主程序的配置文件中定义这些变量,在这里通过名称来使用。以后需要修改数据库连接信息的时候,就可以不同找到这个配置文件,而直接在主程序的配置文件中进行修改就可以了。
第二个文件中,定义了使用 NHibernate 访问数据库的接口,由于在所有的 Dao 对象中都需要通过 SessionFactory 来访问当前的会话对象,定义了接口 INHibernateSessionFactory。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Forbetter.Dao { interface INHibernateSessionFactory { NHibernate.ISessionFactory SessionFactory { set; get; } } }
然后,增加第三个文件, ICustomerDao.cs,这是一个接口定义文件,在 Spring.NET 中通过接口来耦合各个部分,这也是 Spring.NET 代理的特点。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Forbetter.Dao { public interface ICustomerDao { IQueryable<Domain.Customer> GetAllCustomers(); } }
第四个文件为 CustomerDao.cs,实现这两个接口。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using NHibernate.Linq; namespace Forbetter.Dao { [Spring.Stereotype.Repository] public class CustomerDao : ICustomerDao, INHibernateSessionFactory { // Nhibernate 会话支持 public NHibernate.ISessionFactory SessionFactory { set; get; } public IQueryable<Domain.Customer> GetAllCustomers() { NHibernate.ISession session = this.SessionFactory.GetCurrentSession(); var query = session.Query<Domain.Customer>(); var result = from customer in query orderby customer.CompanyName select customer; return result; } } }
其中 SessionFactory 下面使用 Spring.NET 的方式进行注入。
添加第五个文件,objects.xml,在这里使用 Spring.NET 的方式定义数据访问对象,并进行注入。注意生成方式也需要为嵌入的资源。
<?xml version="1.0" encoding="utf-8" ?> <objects xmlns="http://www.springframework.net"> <object id="CustomerDaoImpl" type="ForBetter.Dao.CustomerDao, ForBetter.Dao" > <!-- ref 表示引用的对象 --> <property name="SessionFactory" ref="NHibernateSessionFactory" /> </object> </objects>
现在,这个项目已经完成了,编译一下。项目中的内容应当如下所示:
3. 添加服务项目
通常我们还需要一个业务层,这里我们创建一个 Service 项目来表示一下。
这个项目需要引用的内容会多一些,包括 Domain 项目,Dao 项目,以及 Spring.NET 的三个程序集。Spring.Core, Spring.Data, Spring.Aop。
在项目中同样定义一个服务接口。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Forbetter.Service { public interface ICustomerService { Forbetter.Dao.ICustomerDao CustomerDao { set; get; } IList<Domain.Customer> GetAllCustomers(); } }
然后是服务的实现。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Forbetter.Service { [Spring.Stereotype.Service] [Spring.Transaction.Interceptor.Transaction(ReadOnly=true)] public class CustomerService :ICustomerService { public Forbetter.Dao.ICustomerDao CustomerDao { set; get; } public IList<Domain.Customer> GetAllCustomers() { IQueryable<Domain.Customer> query = this.CustomerDao.GetAllCustomers(); return query.ToList<Domain.Customer>(); } } }
在项目中添加一个名为 Config 的文件夹,在其中添加一个对象定义文件 objects.xml。
<?xml version="1.0" encoding="utf-8" ?> <objects xmlns="http://www.springframework.net"> <object id="CustomerServiceImpl" type="Forbetter.Service.CustomerService" > <!-- ref 表示引用的对象 --> <property name="CustomerDao" ref="CustomerDaoImpl" /> </object> </objects>
完成之后的项目内容如下所示。
4. 定义 Web 项目
终于可以使用 Spring.NET 和 NHibernate 的成果了。Web 项目我们一开始已经创建了,现在需要增加一些内容。
首先,需要添加许多引用,包括对服务项目的引用,对 Domain 项目的引用,对 NHibernate 和 Spring.NET 的引用。还有日志的引用。
注意使用了 Spring.Data.NHibernate32,这是 Spring.NET 对 NHibernate 的支持。
在项目中,添加一个名为 Customer 的文件夹,我们管理客户信息的页面将会保存在这里。
在文件夹中,添加一个标准的 aspx 页面,名为 index.aspx。页面内容如下,定义了一个 GridView 来显示数据。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="index.aspx.cs" Inherits="Sprint_Web_1.Customer.index" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> <asp:GridView runat="server" ID="gvCustomer"></asp:GridView> </div> </form> </body> </html>
将代码文件修改为如下内容。这里使用我们在服务项目中定义的 CustomerService 来访问数据。属性将会通过 Spring.NET 进行注入,这里直接调用服务的方法来获取客户对象的列表。然后通过页面上的 GridView 显示出来。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace Sprint_Web_1.Customer { public partial class index : System.Web.UI.Page { public Forbetter.Service.ICustomerService CustomerService { set; get; } protected void Page_Load(object sender, EventArgs e) { if (!this.IsPostBack) { IList<Forbetter.Domain.Customer> list = this.CustomerService.GetAllCustomers(); this.gvCustomer.DataSource = list; this.gvCustomer.DataBind(); } } } }
在项目中也添加一个 Config 的文件夹。
先添加一个名为 objects.xml 的文件,定义对象注入。
<?xml version="1.0" encoding="utf-8" ?> <objects xmlns="http://www.springframework.net"> <object type="~/Customer/index.aspx"> <property name="CustomerService" ref="CustomerServiceImpl"/> </object> </objects>
然后添加日志配置文件 log4net.xml。这次我们通过 log4net 将日志输出到 Trace 窗口中。
<?xml version="1.0" encoding="utf-8" ?> <log4net> <root> <level value="OFF" /> <appender-ref ref="TraceAppender" /> </root> <logger name="NHibernate"> <level value="DEBUG" /> </logger> <appender name="TraceAppender" type="log4net.Appender.TraceAppender"> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger %ndc - %message%newline" /> </layout> </appender> </log4net>
最后,也是最重要的是 web 项目的根配置文件 web.config ,这是最重要的一个配置文件。
<?xml version="1.0" encoding="utf-8"?> <!-- 有关如何配置 ASP.NET 应用程序的详细消息,请访问 http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <configSections> <!-- Spring 的配置 --> <sectionGroup name="spring"> <section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web"/> <!-- 数据库的配置参数 --> <section name="databaseSettings" type="System.Configuration.NameValueSectionHandler"/> </sectionGroup> <!-- 日志配置 --> <sectionGroup name="common"> <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" /> </sectionGroup> </configSections> <spring> <context> <resource uri="~/Config/objects.xml"/> <!-- 嵌入在程序集中的配置文件 ,首先是程序集名称,然后命名空间,最后文件名, 注意名称的大小写必须完全一致 --> <resource uri="assembly://Forbetter.Dao/Forbetter.Dao.Config/dataAccess.xml"/> <resource uri="assembly://Forbetter.Dao/Forbetter.Dao.Config/objects.xml"/> <resource uri="assembly://Forbetter.Service/Forbetter.Service.Config/objects.xml"/> </context> <!--数据库配置服务器地址--> <databaseSettings> <add key="db.server" value=".\sqlexpress"/> <add key="db.database" value="TSQLFundamentals2008"/> <add key="db.userid" value=""/> <add key="db.password" value=""/> </databaseSettings> </spring> <common> <logging> <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net"> <!-- 使用 log4net 配置文件 --> <arg key="configType" value="FILE-WATCH" /> <arg key="configFile" value="~/Config/log4net.xml" /> </factoryAdapter> </logging> </common> <appSettings> <!-- 为 OpenSessionInViewModule 的 SessionFactory 提供名字 --> <add key="Spring.Data.NHibernate.Support.OpenSessionInViewModule.SessionFactoryObjectName" value="NHibernateSessionFactory"/> </appSettings> <system.web> <compilation debug="true" targetFramework="4.0" /> <httpModules> <!-- Spring 提供的 Module --> <add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web"/> <!-- 由 Spring 自动打开会话,必须提供一个名为 SessionFactory 的会话工厂 使用后,可以使用 SessionFactory 的 GetCurrentSession 方法获取会话 --> <add name="OpenSessionInView" type="Spring.Data.NHibernate.Support.OpenSessionInViewModule, Spring.Data.NHibernate32"/> </httpModules> <httpHandlers> <!-- Spring 提供的处理程序 --> <add verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, Spring.Web"/> <!-- 取消 Spring.NET 对于 Web 服务的处理 --> <!--<add verb="*" path="*.asmx" type="Spring.Web.Services.WebServiceHandlerFactory, Spring.Web"/>--> <add verb="*" path="ContextMonitor.ashx" type="Spring.Web.Support.ContextMonitor, Spring.Web"/> <add verb="*" path="*.ashx" type="Spring.Web.Support.DefaultHandlerFactory, Spring.Web"/> </httpHandlers> </system.web> </configuration>
文件的内容已经增加了注释进行说明。
三. 源代码下载
文件比较大,博客园限制最大为 10M, 所以分为了两个文件。
整个项目的源代码可以从这里下载: