我的NHibernate之路(3)—表间多对多配置篇

本节要点:

1、如何配置表之间多对多的关系

2、多表之间如何进行操作

对于关系型数据库,表之间也多对多的关系也很常见的。在我们实际开发过程中如何进行正确的映射的配置,以及所关联的表之间是如何操作的?这是本文讲述的重点。

开发环境:VS2008 SP1 使用的NHibernate版本:NHibernate-2.1.2.GA-bin。

将上节讨论的学生表与班级表再进行深层次的引入:如果构建一个学生选课的数据库,还需要什么表?表之间的关系如何对应?还是通过LINQ的截图说说表的字段以及表之间的关系【不讨论LINQ与Nhibernate之间的关系,免得又有朋友误解】。图如下:

我的NHibernate之路(3)---表间多对多配置篇

通过图,可以很清楚的看出四张表见的关系。不过我主要说的是下面三张表。

对于学生来说,他可以选择多门课程。对于课程来说,多个学生也可以选择同一门课程。对于学生实体类和课程实体类,他们之间就是一种多对多的关系。顺便给出下面三张表之间的外键。students表与SelectCourse:引用列【ID】与被引用列【Students】,外键名:FK_SelectCourse_Students。Course表与SelectCourse表:引用列【ID】与被引用列【CourseID】,外键名:FK_SelectCourse_Course。被引用类那么他们之间的映射关系如何?

通过上节的说明,一对多是在映射文件中通过one-to-many表示的。大家很自然想到多对多就是通过many-to-many来表示。有了一对多配置的基础,我就说说其中重要的。

Stuents表的映射文件:

1 <?xml version="1.0" encoding="utf-8" ?> 2  <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> 3     <class name="MultiToMultiModel.Student, MultiToMultiModel" table="Students"> 4         <id name="Id" type="Int32" unsaved-value="0"> 5             <column name="ID" length="4" sql-type="int" not-null="true" unique="true"                index="PK_Students"/> 6             <generator class="native" /> 7         </id> 8         <property name="Name" type="String"> 9             <column name="Name" length="50" sql-type="varchar" not-null="false"/>10         </property>11         <property name="Phone" type="String">12             <column name="Phone" length="15" sql-type="varchar" not-null="false"/>13         </property>14         <many-to-one name="Class" class="MultiToMultiModel.Class, MultiToMultiModel">15             <column name="ClassID" length="4" sql-type="int" not-null="false"/>16         </many-to-one>17 18     <bag name="Courses" generic="true"  table="SelectCourse">19       <key column="StudentID" foreign-key="FK_SelectCourse_Students" not-null="false"></key>20       <many-to-many column="CourseID" foreign-key="FK_SelectCourse_Course"               class="MultiToMultiModel.Course,MultiToMultiModel"></many-to-many>21     </bag>22     </class>23  </hibernate-mapping>24

Students对应的实体类:

我的NHibernate之路(3)---表间多对多配置篇我的NHibernate之路(3)---表间多对多配置篇代码

1  2  using System; 3  using System.Collections.Generic; 4  using System.Collections; 5  6  7  namespace MultiToMultiModel 8 { 9     #region Student10 11     /// <summary>12     /// Student object for NHibernate mapped table 'Students'.13     /// </summary>14      public class Student 15         {16         #region Member Variables17         18         protected int _id;19         protected string _name;20         protected string _phone;21         protected Class _class;22         //protected IList _studentSelectCourses;23          protected IList<Course> _courses;24          #endregion25 26         #region Constructors27 28         public Student() { }29 30         public Student( string name, string phone, Class _class )31         {32             this._name = name;33             this._phone = phone;34             this._class = _class;35         }36 37         #endregion38 39         #region Public Properties40 41         public virtual int Id42         {43             get {return _id;}44             set {_id = value;}45         }46 47         public virtual string Name48         {49             get { return _name; }50             set51             {52                 if ( value != null && value.Length > 50)53                     throw new ArgumentOutOfRangeException("Invalid value for Name", value, value.ToString());54                 _name = value;55             }56         }57 58         public virtual string Phone59         {60             get { return _phone; }61             set62             {63                 if ( value != null && value.Length > 15)64                     throw new ArgumentOutOfRangeException("Invalid value for Phone", value, value.ToString());65                 _phone = value;66             }67         }68 69         public virtual Class Class70         {71             get { return _class; }72             set { _class = value; }73         }74 75         public virtual IList<Course> Courses76         {77             get78             {79                 if (_courses == null)80                 {81                     _courses = new List<Course>();82                 }83                 return _courses;84             }85             set { _courses = value; }86         }87          #endregion88         89         }90 91     #endregion92 }93

Course表对应的映射文件:

1 <?xml version="1.0" encoding="utf-8" ?> 2  <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> 3     <class name="MultiToMultiModel.Course, MultiToMultiModel" table="Course"> 4         <id name="Id" type="Int32" unsaved-value="0"> 5             <column name="ID" length="4" sql-type="int" not-null="true" unique="true" index="PK_Course"/> 6             <generator class="native" /> 7         </id> 8         <property name="CourseName" type="String"> 9             <column name="CourseName" length="50" sql-type="varchar" not-null="false"/>10         </property>11         <property name="Teacher" type="String">12             <column name="Teacher" length="50" sql-type="varchar" not-null="false"/>13         </property>14         <property name="Time" type="DateTime">15             <column name="`Time`" length="8" sql-type="datetime" not-null="false"/>16         </property>17         <property name="Address" type="String">18             <column name="Address" length="50" sql-type="varchar" not-null="false"/>19         </property>20 21     <bag name="Students" generic="true" table="SelectCourse" >22       <key column="CourseID" foreign-key="FK_SelectCourse_Course" not-null="false"></key>23       <many-to-many column="StudentID" class="MultiToMultiModel.Student,MultiToMultiModel"             foreign-key="FK_SelectCourse_Students"></many-to-many>24     </bag>25     </class>26  </hibernate-mapping>27

对应的实体类:

1 using System;  2  using System.Collections.Generic;  3  using System.Collections;  4   5   6  namespace MultiToMultiModel  7 {  8     #region Course  9  10     /// <summary> 11     /// Course object for NHibernate mapped table 'Course'. 12     /// </summary> 13      public class Course 14         { 15         #region Member Variables 16          17         protected int _id; 18         protected string _courseName; 19         protected string _teacher; 20         protected DateTime _time; 21         protected string _address; 22         protected IList<Student> _students; 23          24  25         #endregion 26  27         #region Constructors 28  29         public Course() { } 30  31         public Course( string courseName, string teacher, DateTime time, string address ) 32         { 33             this._courseName = courseName; 34             this._teacher = teacher; 35             this._time = time; 36             this._address = address; 37         } 38  39         #endregion 40  41         #region Public Properties 42  43         public virtual int Id 44         { 45             get {return _id;} 46             set {_id = value;} 47         } 48  49         public virtual string CourseName 50         { 51             get { return _courseName; } 52             set 53             { 54                 if ( value != null && value.Length > 50) 55                     throw new ArgumentOutOfRangeException("Invalid value for CourseName", value, value.ToString()); 56                 _courseName = value; 57             } 58         } 59  60         public virtual string Teacher 61         { 62             get { return _teacher; } 63             set 64             { 65                 if ( value != null && value.Length > 50) 66                     throw new ArgumentOutOfRangeException("Invalid value for Teacher", value, value.ToString()); 67                 _teacher = value; 68             } 69         } 70  71         public virtual DateTime Time 72         { 73             get { return _time; } 74             set { _time = value; } 75         } 76  77         public virtual string Address 78         { 79             get { return _address; } 80             set 81             { 82                 if ( value != null && value.Length > 50) 83                     throw new ArgumentOutOfRangeException("Invalid value for Address", value, value.ToString()); 84                 _address = value; 85             } 86         } 87  88         public virtual IList<Student> Students 89         { 90             get 91             { 92                 if (_students == null) 93                 { 94                     _students = new List<Student>(); 95                 } 96                 return _students; 97             } 98             set { _students = value; } 99         }100 101         #endregion102         103         104     }105 106     #endregion107 }108

对于实体类,就不用说了。主要说说映射文件中的节点的配置。

bag:对象集合。集合中的元素可以重复。相当于.Net中的IList或者IList。当然对应的name是相应实体类的属性了。

我个人最为关键的的是KEY、与many-to-mnay两个阶段的配置与理解。首先对于两个实体类,我应该建立他们各自的映射文件,这是最基本的。我就以Course表来说。它与Students表多对多的关系是通过SelectCourse表建立的。要给Course实体类建立与Students的映射关系,唯一的途径就是通过SelectCourse表上的外键FK_SelectCourse_Course。而外键FK_SelectCourse_Course是引用的Course表的主键。

所以对key节点:他对应的column【对应表的列明,这里就不再具体多说】当然是CourseID。

对于many-to-many节点,我是这样理解的。既然是多对多。第一个many指的当然是它自己,即Course,另外一个显然是针对Students。那么Students与Course建立对应关系的唯一途径也只有通过引用在它的主键上建立的外键FK_SelectCourse_Students。后面对应的是实体类Students对应的程序集以及指明Course多对多的实体类Student。

映射文件小结:

key节点:是对于映射文件对应的实体类所说的。many-to-many:是对多对多中另外“多”的一方说的

映射文件的介绍与说明就到这。下面说说它们之间该如何做操作。我仅仅以添加为例进行说明。

添加的需求说明:我希望为一个学生添加他所选的课程,并将此学生添加到一个新的班级中【课程也要求新添加到课程表】。还是直接上代码较为直接:

我的NHibernate之路(3)---表间多对多配置篇我的NHibernate之路(3)---表间多对多配置篇代码

1  //申明对象 2              Class cls = new Class(); 3             Student stu = new Student(); 4             Course c = new Course(); 5  6             SelectCourse _selectCourse = new SelectCourse(); 7  8  9             cls.ClassCode = "03510236";10             cls.ClassStudentses.Add(stu);11             cls.StudentsAmount = 36;12 13             stu.Class = cls;14             stu.Name = "teau";15             stu.Phone = "0897658";16             stu.Courses = new List<Course>();17             stu.Courses.Add(c);18 19 20             c.Address = "Beijing";21             c.CourseName = "C++";22             c.Students = new List<Student>();23             c.Students.Add(stu);24             c.Teacher = "Tao";25             c.Time = DateTime.Now;26 27             _selectCourse.Course = c;28             _selectCourse.Student = stu;29 30 31             ClassBLL cBLl = new ClassBLL();32             CourseBLL courseBLL = new CourseBLL();33             try34             {35                 if (cBLl != null && cls != null)36                 {37                     ClassBLL.AddClass(cls);38                     CourseBLL.AddCourse(c);39                     SelectCourseBLL.AddSelectCourse(_selectCourse);40                 }41             }42             catch (Exception ex)43             {44                 throw ex;45             }

上述添加需求的代码时候就这些,其中关于业务实体类通过ISession会话操作数据库的代码就不再给出。相信只要了解Nhibernate基础只是的都能知道是如何操作的。

说了这么多,多对多的映射到这就说完了。我个人觉得多对多的问题也就是通过中间结构构成的多对多。假如在本例中,我们要完成上述例子中的添加需求,能不能不通过多对多的关系操作呢?我觉得一点问题也没有。因为对Studet表与SelectCourse表,它们对应的实体关系之间就是一对多的关系。同样对SelectCourse实体与Course实体,它们之间也是一对多的关系。如果我们把Student与Course的关系分开来看,其实就是两个一对多的过程。通过一对多的关系也可以解决。

总结:多对多的关系是Nhibernate映射配置中比较难也比较绕的一部分【我个人觉得】。但是只要理解其中key和many-to-many各自配置的作用,以及为何是通过这样配置的,问题也就迎刃而解了。

就写到这了,希望对各位有所帮组,若有理解或者表述有误的也希望大侠们踊跃拍砖!
原文链接: https://www.cnblogs.com/tyb1222/archive/2010/09/25/1834890.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/15460

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月7日 下午3:24
下一篇 2023年2月7日 下午3:26

相关推荐