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


      本节要点:

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

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

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

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

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

      

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

      对于学生来说,他可以选择多门课程。对于课程来说,多个学生也可以选择同一门课程。对于学生实体类和课程实体类,他们之间就是一种多对多的关系。顺便给出下面三张表之间的外键。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对应的实体类:

    代码
    1
    2  using System;
    3  using System.Collections.Generic;
    4  using System.Collections;
    5
    6
    7  namespace MultiToMultiModel
    8 {
    9 #region Student
    10
    11 /// <summary>
    12 /// Student object for NHibernate mapped table 'Students'.
    13 /// </summary>
    14   public class Student
    15 {
    16 #region Member Variables
    17
    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 #endregion
    25
    26 #region Constructors
    27
    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 #endregion
    38
    39 #region Public Properties
    40
    41 public virtual int Id
    42 {
    43 get {return _id;}
    44 set {_id = value;}
    45 }
    46
    47 public virtual string Name
    48 {
    49 get { return _name; }
    50 set
    51 {
    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 Phone
    59 {
    60 get { return _phone; }
    61 set
    62 {
    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 Class
    70 {
    71 get { return _class; }
    72 set { _class = value; }
    73 }
    74
    75 public virtual IList<Course> Courses
    76 {
    77 get
    78 {
    79 if (_courses == null)
    80 {
    81 _courses = new List<Course>();
    82 }
    83 return _courses;
    84 }
    85 set { _courses = value; }
    86 }
    87 #endregion
    88
    89 }
    90
    91 #endregion
    92 }
    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 #endregion
    102
    103
    104 }
    105
    106 #endregion
    107 }
    108  

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

      bag:对象集合。集合中的元素可以重复。相当于.Net中的IList或者IList<T>。当然对应的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:是对多对多中另外“多”的一方说的

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

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

    代码
    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 try
    34 {
    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各自配置的作用,以及为何是通过这样配置的,问题也就迎刃而解了。

      就写到这了,希望对各位有所帮组,若有理解或者表述有误的也希望大侠们踊跃拍砖!

  • 相关阅读:
    操作系统的发展与分类
    kinect1在ros环境下跑orb_slam2
    ubuntu16.04如何设置局域网
    make编译时出现virtual memory exhausted: Cannot allocate memory
    ubuntu下载百度云文件
    ubuntu16.04安装teamviewer
    安装pangolin链接
    运行 roslaunch gazebo_ros empty_world.launch提示有错误,没有gzserver和gzclient
    Ubuntu16.04 安装有道词典
    [Qt插件]-02创建应用程序插件(插件化开发的一种思路)
  • 原文地址:https://www.cnblogs.com/tyb1222/p/1834890.html
Copyright © 2020-2023  润新知