1. 程式人生 > >NHibernate多對多關聯對映的實現

NHibernate多對多關聯對映的實現

上次用EF演示了資料庫多對多關係的操作,這次我們還是引用上次的案例,來演示如何在C#當中使用NHibernate。

首先介紹一下NHibernate框架的來源。熟悉Java程式設計的讀者肯定知道Hibernate這個ORM。NHibernate就來源於Java中著名的ORM框架—Hibernate,這點從名稱當中就能夠知道。目前NHibernate的最新版本是3.3.3,好像有一陣子沒有update了,說明當前的版本也比較穩定了。具體的資料可以到官網查詢:http://nhforge.org/

1、下載NHibernate

官網首頁就有下載連結,直接下載就可以了。

下載好之後會得到一個zip包。


我們就地解壓可以看到如下目錄和檔案:


我們重點關注以下目錄的內容:

Configuration_Templates目錄:預設提供的一些配置模板。有支援Oracle、Sql Server、MySQL等等。

Required_Bins目錄:這裡面存放了我們開發時常用的dll檔案。其中的兩個xsd檔案是能夠提供智慧提示的檔案,我們需要將它們倆複製到你本地的VS的Schemas目錄下,比如我的目錄為:D:\Program Files (x86)\Microsoft Visual Studio 11.0\Xml\Schemas 。

複製好之後,重啟VS,在我們寫Hibernate配置檔案時就有了智慧提示了。


準備工作做好之後,我們就可以正式演示。

2、建立一個類庫專案Model

我們定義好兩個類,分別為Student和Subject,為了便於管理,我們將它們放到Entity資料夾裡,但名稱空間仍為Model。

namespace Model
{
    public enum Gender { Female, Male }

    public class Student
    {
        public virtual int? StudentId { get; set; }
        public virtual string StudentName { get; set; }
        public virtual Gender Gender { get; set; }
        public virtual DateTime? BirthDay { get; set; }

        public virtual IList<Subject> Subjects { get; set; }
    }
}
namespace Model
{
    public class Subject
    {
        public virtual int? SubjectId { get; set; }
        public virtual string SubjectName { get; set; }

        public virtual IList<Student> Students { get; set; }
    }
}
這是一個典型的多對多的應用場景。一個學生可以選修多個課程,一個課程可以被多個學生選修。

接下來我們再建立相應的Hibernate配置檔案(就是普通的xml檔案,取名為Student.hbm.xml和Subject.hbm.xml)。

Student.hbm.xml:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Model" namespace="Model">
  <class name="Student" table="T_Student" lazy="true">
    <id name="StudentId"  type="int" column="StudentId">
      <generator class="native"/>
    </id>
    <property name="StudentName" type="string" column="StudentName">
      <column name="StudentName" length="50"/>
    </property>
    <property name="Gender" type="Gender" column="Gender">
      <column name="Gender" length="4"/>
    </property>
    <property name="BirthDay" type="datetime" column="BirthDay">
      <column name="BirthDay" length="20"/>
    </property>
    <bag name="Subjects" table="T_Student_Subject">
      <key column="StudentId"/>
      <many-to-many class="Subject" column="SubjectId"/>
    </bag>
  </class>
</hibernate-mapping>
Subject.hbm.xml:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Model" namespace="Model">
  <class name="Subject" table="T_Subject" lazy="true">
    <id name="SubjectId" type="int" column="SubjectId">
      <generator class="native"/>
    </id>
    <property name="SubjectName" type="string">
      <column name="SubjectName" length="50"/>
    </property>
    <bag name="Students" table="T_Student_Subject">
      <key column="SubjectId"/>
      <many-to-many class="Student" column="StudentId"/>
    </bag>
  </class>
</hibernate-mapping>
便於管理我們同樣的放到Config目錄下(自己建立的資料夾)。

同時修改兩個xml檔案的生成操作由內容變為嵌入的資源(在vs中右鍵xml檔案選擇屬性)


3、建立一個控制檯應用程式

表和實體對應的內容已經定義好,下面關鍵的就是要寫程式碼來測試NHibernate了,本著儘量降低學習難度的原則,我這裡就用控制檯應用程式來驗證(你也可以新建一個類庫專案,然後用VS的單元測試或者第三方測試工具NUnit進行驗證)。

首先將下載的開發包裡面的Configuration_Templates資料夾下的MSSQL.cfg.xml複製到控制檯應用程式中(為方便管理,我新建了一個Config資料夾,並把這個xml檔案放到這裡面,重新命名為hibernate.cfg.xml)。

修改這個xml檔案內容為:

<?xml version="1.0" encoding="utf-8"?>
<!-- 
This template was written to work with NHibernate.Test.
Copy the template to your NHibernate.Test project folder and rename it in hibernate.cfg.xml and change it 
for your own use before compile tests in VisualStudio.
-->
<!-- This is the System.Data.dll provider for SQL Server -->
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
  <session-factory name="NHibernate.Test">
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <property name="connection.connection_string">
      Server=.;database=nhibernateTest;uid=sa;pwd=123456;
    </property>
    <property name="adonet.batch_size">10</property>
    <property name="show_sql">true</property>
    <property name="hbm2ddl.auto">update</property>
    <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
    <mapping assembly="Model"/>
  </session-factory>
</hibernate-configuration>
注意這裡面的一些節點的配置。比如mapping assembly裡面的Model,就是指的是程式集的名稱。同時將此檔案的複製到輸出目錄方式修改為始終複製。


接下來,給控制檯專案新增兩個dll的引用,分別為Iesi.Collections.dll和NHibernate.dll,也是在Required_Bins資料夾裡面。

新增好引用,我們建立一個新的類NHibernateTest來寫關鍵性程式碼。

namespace NHibernateDemo
{
    public class NHibernateTest
    {
        private ISessionFactory _sessionFactory;
        public ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    var cfg = new NHibernate.Cfg.Configuration().Configure("Config/hibernate.cfg.xml");
                    _sessionFactory = cfg.BuildSessionFactory();
                }
                return _sessionFactory;
            }
        }

        public void TestInit()
        {
            using (ISession session = SessionFactory.OpenSession())
            {
                IList<Subject> subjects = new List<Subject>() 
                {
                     new Subject { SubjectName = "數學" }, 
                     new Subject { SubjectName = "英語" },
                     new Subject { SubjectName = "計算機" },
                };

                IList<Student> students = new List<Student>()
                {
                    new Student
                    {
                        StudentName = "guwei4037",
                        Gender = Gender.Male,
                        BirthDay = new DateTime(1984, 11, 25),
                        Subjects = subjects.Where(x => x.SubjectName == "數學" || x.SubjectName == "計算機").ToArray(),
                    },
                    new Student
                    {
                        StudentName = "gary.gu",
                        Gender = Gender.Female,
                        BirthDay = new DateTime(1987, 9, 15),
                        Subjects = subjects.Where(x => x.SubjectName == "數學" || x.SubjectName == "英語").ToArray(),
                    },
                };

                ITransaction tran = session.BeginTransaction();
                try
                {
                    foreach (var subject in subjects)
                    {
                        session.Save(subject);
                    }

                    foreach (var student in students)
                    {
                        session.Save(student);
                    }

                    tran.Commit();
                }
                catch (Exception ex)
                {
                    tran.Rollback();
                    throw ex;
                }
            }
        }
    }
}
這是一個帶事務的多表插入的操作。

最後在Main方法中,寫入簡單的呼叫方法。

 public class program
    {
        public static void Main(string[] args)
        {
            NHibernateTest test = new NHibernateTest();
            test.TestInit();
        }
    }
在執行這個程式之前,還要做一件事,就是要在你的Sql Server中新建一個空的資料庫nhibernateTest,否則會提示登入失敗。

好了,這時我們已經準備好了一切,讓我們執行一下這個控制檯應用程式吧。

由於我們在hibernate.cfg.xml檔案中定義了輸入sql,所以會看到視窗中的內容。


好,沒有報錯。我們開啟Sql Server看一下最終的結果。


而且資料庫的表、主外來鍵的關聯以及資料都為我們自動生成了。