LINQ学习之旅——第二站"LTQ"之标准数据库操作(增查删改)

  今天要讲解主要内容是关于LINQ TO SQL中的标准数据库操作:插入(Insert)、查询(Select)、更新(Update)以及删除(Delete),凡是涉及到数据库方面的都会使用这些操作。而这些操作对大家来说是再熟悉不过了,所以这节内容在理解上没有任何困难。下面就来讲解一下这四个操作在LINQ TO SQL中的应用。

  在介绍四个操作内容之前,先来简单说一下泛型接口IQueryable<T>。LINQ TO SQL的大部分从操作符都是作为该接口的扩展方法。因为LINQ TO SQL中使用了大量表达式树,为了实现表达式树的运行时编译优化功能,被操作对象必须暴露更多额外的信息,而继承泛型接口IEnumerable<T>的IQUeryable<T>泛型接口提供了足够的信息使能够满足LINQ TO SQL的即时优化编译要求。下面介绍四个标准数据库操作:

  1.插入操作:

  在LINQ TO SQL中的插入操作其实非常简单,在上一节DataContext对象详解的示例代码中就提到过,新建一个实体类对象,然后把实体类对象添加入DataContext类的成员方法GetTable返回的一个Table<T>的集合中,或添加到类型为EntitySet<T>的集合中,其中的T代表实体类,最后调用DataContext对象的SubmitChanges方法,提交新增结果给数据库。下面是两个关于插入操作的示例(注:本文中所涉及到的Student、Course以及Student_Course实体类请参考对象——关心映射的内容 ):

i.普通插入

普通插入
 1 string str_sql ="Data Source=localhost;Initial Catalog=DB_Student;User ID=sa;Password=king";
2 DataContext dc =new DataContext(str_sql);
3
4 //实例化实体类对象
5 Student newstudent =new Student()
6 {
7 No ="20030012",
8 Name ="古筝",
9 Dept ="表演系",
10 Age =23,
11 Sex =""
12 };
13
14 //将对象添加到Table<T>
15 dc.GetTable<Student>().InsertOnSubmit(newstudent);
16
17 //提交
18 dc.SubmitChanges();

ii.结果(物理表student)

i.一对多关系插入

一对多关系插入
 1 string str_sql ="Data Source=localhost;Initial Catalog=DB_Student;User ID=sa;Password=king";
2 DataContext dc =new DataContext(str_sql);
3
4 //实例化实体类对象
5 Course newcourse =new Course()
6 {
7 No ="ky030011",
8 Name ="声乐与语言发音",
9 Credit=5,
10 };
11
12 var student=dc.GetTable<Student>().Where(s=>s.No=="20030012").Single();
13 //实例化实体类对象
14 Student_Course sc =new Student_Course()
15 {
16 Cno = newcourse.No,
17 Sno = student.No,
18 Grade =95,
19 };
20
21 newcourse.Students.Add(sc);
22
23 //将对象添加到Table<T>
24 dc.GetTable<Course>().InsertOnSubmit(newcourse);
25
26 //提交
27 dc.SubmitChanges();

ii.结果

①物理表course:

②物理表sc:

  2.查询操作:

  LINQ TO SQL中的标准查询语句和LINQ TO OBJECT中的非常类似,但是它们在底层实现上有很大区别:1.LINQ TO SQL查询语句返回的结果类型为IQueryable<T>,而非IEnumerable<T>;2.LINQ TO SQL的大部分标准查询操作符都是定义在IQueryable<T>类型中的扩展方法,而不像LINQ TO OBJECT中是定义在类型IEnumerable<T>上的,另外IQueryable<T>其实继承了IEnumerable<T>类的,所以LINQ TO SQL上的查询操作符比LINQ TO OBJECT更多,要想在LINQ TO SQL上使用LINQ TO OBJECT的查询符,那么就需要使用AsEnumerable操作符进行转换,这个在之前的延时标准查询符(下)一节中有详细介绍;3.LINQ TO SQL的查询语句被转换成标准的SQL语句,而LINQ TO OBJECT中的查询语句是被转换成IL代码,LINQ TO SQL使用表达式树来实现编译时动态转换成SQL语句发送给数据库;4.LINQ TO SQL查询被转换成SQL语言后在数据库被执行,而不像LINQ TO OBJECT中的查询是在客户端被执行的。虽然LINQ TO SQL和LINQ TO OBJECT在查询上有很多的差别,但它们也有相同之处,就是LINQ TO SQL和LINQ TO OBJECT一样都有延时查询的特性,也就是说对数据库的查询是在必要时候才执行查询,比如访问一个实体类对象的属性时,而不是在定义的时候就立即进行查询下面通过实例来说明LINQ TO SQL中延时查询的特性:

i.延时查询

延时查询
 1 string conn ="Data Source=localhost;Initial Catalog=DB_Student;User ID=sa;Password=king";
2 DataContext dc =new DataContext(conn);
3
4 //将SQL语句显示在控制台
5 dc.Log = Console.Out;
6
7 Table<Student> Tb_Students = dc.GetTable<Student>();
8
9 Console.WriteLine("LINQ TO SQL查询符转化的SQL语句:");
10
11 //查询
12 var students = from s in Tb_Students where s.Age >2 select s;
13
14 //列举
15 //foreach (var stu in students.Take(3))
16 //{
17 // Console.WriteLine(stu.ToString());
18 //}
19
20 Console.Read();

ii.结果

从运行结果中可以看到尽管示例代码中使用了查询语句,但没有任何向数据库发送的SQL语句,现在把列举部分的注释去掉,再来看看结果如何:

这时候出现了相应的SQL语句,也就是说在真正用到查询结果时(比如图中通过foreach来列举查询结果),才会去发送并执行SQL语句。当实体类之间存在一对多的关系时,可以用属性(attribute)Association来进行关联,一旦实现了关联操作,那么在向数据库中查询一个物理表记录生成实体类对象时,也会附带着相关联物理表生成的实体类对象。这样就方便了关联数据的访问,但也许有读者会问,那如果要查询的实体类对象,比如Course类,它有关联的实体类Student_Course,那么每次查询类Course对象,都会连带去查询相对应的实体类Student_Course对象,而不管在这之后的操作中用不用到实体类Student_Course对象。这样不就在性能上有损失了。其实并非如此,LINQ TO SQL中有一个称为延时载入的特性,也就是说只有用到与Course实体类相关联的实体类Student_Course对象时,才会发去SQL语句去查询相关联的物理表的记录生成实体类对象。以下是关于延时载入特性的说明示例:
i.延时载入

延时载入
 1 string conn ="Data Source=localhost;Initial Catalog=DB_Student;User ID=sa;Password=king";
2 DataContext dc =new DataContext(conn);
3
4 //将SQL语句显示在控制台
5 dc.Log = Console.Out;
6
7 Console.WriteLine("LINQ TO SQL查询符转化的SQL语句:");
8
9 Table<Course> Tb_Courses = dc.GetTable<Course>();
10
11 //查询
12 var course = Tb_Courses.Where(c => c.No =="ky030002").Single();
13
14 //foreach (var sc in course.Students)
15 //{
16 // Console.WriteLine(sc.ToString());
17 //}
18
19 Console.Read();

ii.结果

从结果中可以看到向数据库发送SQL语句只是查询物理表course里的记录,而并没有把相关的物理表sc中对应记录也查询出来。现在把上述的列举代码的注释去掉,再来看看运行结果:

默认条件下,延时载入是自动支持的,但有时候在实际的运用中需要明确地要求在生成实体类对象的同时一并生成该对象的关联成员,而不是等到使用该关联成员时,才载入,这就需要立即载入的功能,而LINQ TO SQL中就提供了DataLoadOptions类的操作符LoadWith<T>来通知DataContext对象进行立即载。下面是关于立即载入功能的说明示例:

i.立即载入

立即载入
 1 string conn ="Data Source=localhost;Initial Catalog=DB_Student;User ID=sa;Password=king";
2 DataContext dc1 =new DataContext(conn);
3
4 Table<Course> Tb_Courses1 = dc1.GetTable<Course>();
5
6 //将SQL语句显示在控制台
7 dc1.Log = Console.Out;
8
9 //实例化类DataLoadOptions
10 DataLoadOptions dlo =new DataLoadOptions();
11
12 //指定在载入Course对象时一并载入关联成员Students(来自Student_Course类的对象集合)
13 dlo.LoadWith<Course>(c => c.Students);
14
15 //将类DataLoadOptions的对象dlo赋值给DataContext对象
16 dc1.LoadOptions = dlo;
17
18 Console.WriteLine("LINQ TO SQL查询符转化的SQL语句:");
19 //查询
20 var courses = Tb_Courses1.Where(c => c.No =="ky030002").Single();
21
22 Console.Read();

ii.结果: 

使用Association属性仅限于只有在数据库中明确为需要关联的物理表建立外键的情况,而在有些实际应用中,并没有对数据库中的物理表建立明确的主外键关系,但仍然需要对关联的多个表进行查询,那么这时候就要用到LINQ TO SQL中的标准操作符Join了,它和SQL中的Join一样,有两种表示内连接(inner join)的语法,还有它和SQL SERVER中的SQL一样也可以定义外连接(outer join),下面是LINQ TO SQL中Join操作符使用的说明示例:

i.Join操作符实现内连接和外连接

Join操作符
 1 string conn ="Data Source=localhost;Initial Catalog=DB_Student;User ID=sa;Password=king";
2 DataContext dc =new DataContext(conn);
3
4 var students2 = dc.GetTable<Student>();
5 var courses2 = dc.GetTable<Course>();
6 var scs2 = dc.GetTable<Student_Course>();
7
8 Console.WriteLine("内连接:");
9 var scs_1 = from s in students2
10 join sc in scs2
11 on s.No equals sc.Sno into sscs //放入临时对象sscs
12 from ssc in sscs
13 join c in courses2
14 on ssc.Cno equals c.No
15 select new { Sname = s.Name, Cname = c.Name, Grade = ssc.Grade };
16 //
17 //var scs_2 = from s in students2
18 // from c in courses2
19 // from sc in scs2
20 // where s.No == sc.Sno && c.No == sc.Cno
21 // select new { Sname = s.Name, Cname = c.Name, Grade = sc.Grade };
22
23 Console.WriteLine("学生选课情况:");
24 foreach (var scg in scs_1.AsEnumerable().Reverse().Take(5))
25 {
26 Console.WriteLine(scg.ToString());
27 }
28
29 Console.WriteLine();
30
31 Console.WriteLine("外连接:");
32 var scs_3 = from s in students2
33 join sc in scs2
34 on s.No equals sc.Sno into sscs //放入临时对象sscs
35 from ssc in sscs.DefaultIfEmpty()//DefaultIfEmpty实现外连接
36 join c in courses2
37 on ssc.Cno equals c.No into sccs //放入临时对象sccs
38 from scc in sccs.DefaultIfEmpty()//DefaultIfEmpty实现外连接
39 select new { Sname = s.Name, Cname =scc.Name, Grade = ssc.Grade };
40
41 Console.WriteLine("学生选课情况:");
42 foreach (var scg in scs_3.AsEnumerable().Reverse().Take(5))
43 {
44 Console.WriteLine(scg);
45 }
46
47 Console.Read();

ii.结果

  3.更新操作:

  同样的更新操作也十分简单,修改实体类对象的属性,然后调用SubmitChanges方法,提交更改。但要注意的是在LINQ TO SQL中对主键的修改是不允许的,下面是关于更新操作的示例:

i.更新操作

更新操作
 1 string str_sql ="Data Source=localhost;Initial Catalog=DB_Student;User ID=sa;Password=king";
2 DataContext dc =new DataContext(str_sql);
3
4 var students = dc.GetTable<Student>();
5
6 Console.WriteLine("修改前:");
7 foreach (var stu in students.Take(3))
8 {
9 Console.WriteLine(stu.ToString());
10 }
11
12 foreach(var stu in students)
13 {
14 stu.Age +=1;
15 }
16
17 dc.SubmitChanges();
18
19 dc.Refresh(RefreshMode.OverwriteCurrentValues, students);
20
21 Console.WriteLine("修改后:");
22 foreach (var stu in students.Take(3))
23 {
24 Console.WriteLine(stu.ToString());
25 }
26
27 Console.WriteLine("\n");
28
29 Console.Read();

ii.结果

  4.删除操作:

  LINQ TO SQL中的删除操作和插入操作类似,可以在DataContext对象的方法GetTable的返回值Table<T>,基础上调用DeleteOnSumbit方法,它允许将一个或多个实体类对象从Table<T>集合中被删除。下面是删除操作的示例:

i.删除操作

删除操作
 1 string str_sql ="Data Source=localhost;Initial Catalog=DB_Student;User ID=sa;Password=king";
2 DataContext dc =new DataContext(str_sql);
3
4 Console.WriteLine("学生:");
5 var student2 = dc.GetTable<Student>().Where(s => s.No =="20030012").Single();
6 Console.WriteLine(student2.ToString());
7
8 Console.WriteLine("选课:");
9 var courses = dc.GetTable<Student_Course>().Where(s => s.Sno =="20030012");
10 foreach (var c in courses)
11 {
12 Console.WriteLine(c.Course.ToString());
13 }
14
15 dc.GetTable<Student_Course>().DeleteAllOnSubmit(courses);
16 dc.GetTable<Student>().DeleteOnSubmit(student2);
17
18 dc.SubmitChanges();
19
20 dc.Refresh(RefreshMode.OverwriteCurrentValues,courses);
21 Console.WriteLine("删除操作后,学号为20030012的学生选课情况:");
22 foreach (var c in courses)
23 {
24 Console.WriteLine(c.Course.ToString());
25 }
26
27 Console.Read();

ii.结果

posted @ 2011-09-14 22:00  Rookie_J  阅读(2063)  评论(6编辑  收藏  举报