LINQ学习之旅——LINQ TO SQL继承支持(End Chapter)
大家还记得之前在LINQ TO SQL的对象——关系映射(ORM)一节中所提到过的一个内联属性InheritanceMapping,它用于建立实体类之间的继承关系。那么今天就详细讲解一下LINQ TO SQL中是如何实现单表继承的。内容不会太复杂,但比较重要,就作为LINQ TO SQL的补充吧!
那么何谓单表继承?大家都知道面向对象中的继承所体现是可扩展性和可重用性,重用的是基类的特性,扩展的是自己独有的特性。那么转换到数据库物理表,就是加入一个用于区分不同派生实体类的字段,以及各自派生实体类属性(Property)对应的字段。并对该基类和基类中用于出区分不同派生类的属性(Property)设置相应的内联属性(Attribute)。因为基类和这些派生类所有的属性都来自于基类所映射的这一张物理表,所以被称为单表继承。下面通过具体的示例来说明LINQ TO SQL中实现单表继承的过程,仍然以Student实体类为例(具体参考ORM章节)。
假如现在要求能够在学生中区分出研究生和本科生,那么首先需要对Student实体类所对应的物理表stduent做相应的修改,为了不与之前所作的示例在运行中产生冲突,这里在数据库中另外建立一张表studentbase,其他字段和表student中一样,另外再加入用于区分不同派生类的字段stype(值U代表本科生,G代表研究生),以及增加字段spec 专业(只有本科生才有),字段tno 指导教师,research 研究方向(只有研究生才有);
接下来对这三张物理表建立相应的实体类:
①StudentBase类(基类):
1 //设置基类识别器,当识别器属性的值为S时,实例化类StudentBase,
2 //当没有一个识别器属性值可以对应时,默认实例化类StudentBase
3 [InheritanceMapping(Code = "S", Type = typeof(StudentBase), IsDefault = true)]
4 //设置派生类识别器,当识别器属性值为U时,实例化类UnderGraduate
5 [InheritanceMapping(Code = "U", Type = typeof(UnderGraduate))]
6 //设置派生类识别器,当识别器属性值为G时,实例化类Graduate
7 [InheritanceMapping(Code = "G", Type = typeof(Graduate))]
8 [Table(Name="dbo.studentbase")]
9 class StudentBase
10 {
11 [Column(Name = "sno", DbType = "char(8) NOT NULL")]
12 public string No { get ; set ; }
13
14 [Column(Name = "sname", DbType = "varchar(10) NOT NULL")]
15 public string Name { get; set; }
16
17 [Column(Name = "sdept", DbType = "varchar(10)", CanBeNull = true)]
18 public string Dept { get; set; }
19
20 [Column(Name = "ssex", DbType = "char(2)", CanBeNull = true)]
21 public string Sex { get; set; }
22
23 [Column(Name = "sage", DbType = "int", CanBeNull = true)]
24 public int Age { get; set; }
25
26 //IsDiscriminator用来设置该属性为识别器属性
27 [Column(Name = "stype", DbType = "char(1)", CanBeNull = true,IsDiscriminator=true)]
28 public char Type { get; set; }
29 }
②UnderGraduate类(本科生):
1 //本科生类继承与学生基类
2 class UnderGraduate:StudentBase
3 {
4 [Column(Name = "spec", DbType = "varchar(10)", CanBeNull = true)]
5 public string Spec { get; set; }
6
7 public override string ToString()
8 {
9 return "{ No=" + No + ", Name=" + Name + ", Spec=" + Spec + "}";
10 }
11 }
③Graduate类(研究生):
1 //研究生类继承与学生基类
2 class Graduate:StudentBase
3 {
4 [Column(Name = "tno", DbType = "char(8)",CanBeNull=true)]
5 public string Tno { get; set; }
6
7 [Column(Name = "research", DbType = "varchar(20)",CanBeNull=true)]
8 public string Research { get; set; }
9
10 public override string ToString()
11 {
12 return "{No=" + No + ", Name=" + Name + ", Tno=" + Tno + ", Research=" + Research + "}";
13
14 }
15 }
其中属性(Attribute)InheritanceMapping需要和属性识别器IsDiscriminator一起使用,用于当属性识别器取不同的值时,所对应的实例化的实体类类型。而InheritanceMapping属性中参数IsDefault用于当没有与设置为属性识别器的属性的值对应的实体类时,限定哪个为默认的实体类。完成了实体类之间继承映射的设置,那么它有什么用呢?比如:当在学生记录集合中查询哪些学生是研究生,哪些是本科生时,我们不再需要通过比较属性(Property)值的方式来查找,而是直接通过具体的派生实体类的类型来查找相应类型的学生就可以了。常用的使用方式有四种,分别为:IS、AS、OfType以及Cast方式;下面通过示例来具体说明这些方法的使用:
①使用继承映射特性来查找相应类型学生:
1 static void Main(string[] args)
2 {
3 DataContext dt = new DataContext("Data Source=localhost;Initial Catalog=DB_Student;User ID=sa;Password=king");
4
5 dt.Log = Console.Out;
6
7 //Is方式查询研究生
8 var graduates = from g in dt.GetTable<StudentBase>() where g is Graduate select g;
9 //或As方式
10 //var graduates = (from g in dt.GetTable<StudentBase>() select g as Graduate).Where(s=>s!=null);
11 Console.WriteLine("学生中为研究生:");
12 foreach (var g in graduates)
13 {
14 Console.WriteLine(g.ToString());
15 }
16
17 Console.WriteLine("\n");
18
19 //OfType方式查询本科生
20 var undergraduates=from u in dt.GetTable<StudentBase>().OfType<UnderGraduate>() select u;
21 //或Cast方式
22 //var undergraduates = (from u in dt.GetTable<StudentBase>().Cast<UnderGraduate>() select u).Where(u=>u!=null);
23 Console.WriteLine("学生中为本科生:");
24 foreach (var u in undergraduates)
25 {
26 Console.WriteLine(u.ToString());
27 }
28
29 Console.Read();
30 }
②结果:
从运行结果中SQl语句就可以清楚地看到系统是如果运用继承映射特性来完成对特定类型记录的查找的。所以LINQ TO SQL中单表继承就这么回事,并不复杂。当然单表继承也有不足的地方:因为单表映射限制,如果派生类的属性映射来自于不同的物理表。而且这样的业务需求是很正常的,比如把学生详细信息(联系方式和地址)从学生信息表中抽取出来单单为一张表。这时单表继承就无法实现了。
LINQ TO SQL中的继承支持就讲到这里,到此,LINQ学习之旅系列的讲解也就告以段落了。看完整个系列的博友也许会发现,其实LINQ技术还是有许多不足和缺陷的地方,尤其LINQ TO SQL(ORM框架)。所以如果想更加深入、清晰地学习ORM框架的话,建议大家可以去学习一下当前比较主流的一些ORM框架,比如.Net系列的NHibernate、Java系列的Hibernate。也许有博友会问那LINQ TO SQL技术不是白学了,其实不然,IT技术就是在不断更新和发展中前进的,同样的,在ORM框架的不断发展中,学习和比较那些优秀的框架,看到它们的不足和优势,也是不断提升自己能力的一种方式。个人认为LINQ TO SQL可以到作为我们进一步学习ORM框架的基础。
唉~废话不多说了!最后,还是一样,深深地感谢一直陪伴着这一系列走来的博友们的支持和关注。
END