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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值