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, 所以分为了两个文件。

整个项目的源代码可以从这里下载:

项目文件1

项目文件2

原文地址:https://www.cnblogs.com/haogj/p/2623155.html