linq技术研究.docx
- 文档编号:13133034
- 上传时间:2023-06-11
- 格式:DOCX
- 页数:10
- 大小:22.55KB
linq技术研究.docx
《linq技术研究.docx》由会员分享,可在线阅读,更多相关《linq技术研究.docx(10页珍藏版)》请在冰点文库上搜索。
linq技术研究
Linq技术研究
一、Linq简介
LINQ,语言级集成查询(LanguageIntegratedQuery)
LINQ提供了一条更常规的途径即给.NetFramework添加一些可以应用于所有信息源(allsourcesofinformation)的具有多种用途(general-purpose)的语法查询特性(queryfacilities),这是比向开发语言和运行时(runtime)添加一些关系数据(relational)特性或者类似XML特性(XML-specific)更好的方式。
LINQ是微软将在C#3.0中将推出的语言集成查询技术,许多人也将LINQ叫做微软的ORM。
LINQ不仅仅针对关系数据库,它只是解决一个问题Data!
=Object,也就是说他解决的就是Data=Object.。
作为底层框架,可以为ORM实现提供更强大的基础平台。
LINQtoSQL集成到应用程序中需考虑的一些问题:
1、结果集的返回是IQueryable还是List,还是应该扩展为T,。
2、需要一个分页功能;LINQtoSQL本身已经有API提供了分页功能了,不过只有排序或包含标识列的查询中支持Skip方法,看看下面的分页API,多么简单:
returnq.Skip((currentPage-1)*pageSize).Take
3、需要一个动态排序功能,这里List的局限性出来了,传统的做法可能需要用一个dynamic参数来传递需要排序的列然后到SP当中来执行,但我们已经不打算使用SP了,也没有动态sql语句,所有的东西都是强类型的,然后有LINQtoSQL在运行时来帮我们转换为T-SQL语句。
首先List的话,我们不知道到底哪个字段要排序,如果使用字符串作为参数的话,例如放一个stringsortBy作为方法的参数,那么在方法体内就需要做if…else或者switch的判断,而且还要考虑倒序还是正序的排序要求,而且你还要hardcode,很明显麻烦来了.然而如果使用IQueryable却可以很好的解决所有的这些问题.但是IQueryable不能跨assembly,一旦跨了assembly的话,你无法使用var来引用匿名类里面的property,绑定到control是没有问题的,但是客户端的动态查询却成了问题,因为你根本不知道匿名类是什么.那么选择IQueryable,我们选择返回IQueryable给客户端,分页/排序都没有任何问题.
二、Linq语法本质
简单一点的说,Linq的本质=语法糖(自动属性)+语法糖(初始化器)+语法糖(具有隐式类型的局部变量)+语法糖(匿名类型)+语法糖(扩展方法)+语法糖(更强的类型自动推断)+语法糖(Lambda表达式)+语法糖(编译为Lambda表达式树)+类库(Lambda表达式树)+类库(LinqtoSql)+类库(LinqtoObject)+类库(LinqtoXml)+类库(Linqto其他扩展),看一下下面的实例:
1、自动属性
class Class
{
//C#2.0 属性
//private int _id;
//public int ID
//{
// get {
// return _id;
// }
// set
// {
// _id = value;
// }
//}
//C#3.0 属性 可以给get set加访问修饰符
public int ID { get; private set; }
public string Name { get; set; }
public Class(int id)
{
//加了private之后的属性只能在类的内部访问
this.ID = id;
}
}
本质:
和原来的属性没啥两样,简化了语法而已。
2、初始化器
private static void Initializer()
{
//C#2.0 对象初始化
//Class c = new Class
(1);
//c.Name = "终极一班";
//C#3.0 对象初始化器
Class c = new Class
(1) { Name = "终极一班" };
//C#2.0 集合初始化
//ClassCollection list = new ClassCollection();
//list.Add(c);
//C#3.0 集合初始化器
ClassCollection list = new ClassCollection
{
new Class
(1) { Name="终极一班"},
new Class
(2){Name="终极二班"}
};
foreach (Class item in list)
{
Console.WriteLine(item.ID + " " + item.Name);
}
}
本质:
和原来的构造函数初始化或构造后通过属性初始化没啥两样,简化了语法而已。
对Linq的意义:
和匿名类型结合起来构造查询结果集合里面的新元素类型。
3、具有隐式类型的局部变量
private static void Var()
{
// 编译过后的结果实际是 int i=1; var并不是动态变量,它的类型实际上是c#编译器通过上下文推断是int
var i = 1;
var d = DateTime.Now;//=后面支持各种类型
var a = new int[] { 1, 2, 3 };//var也支持数组
foreach (var item in a)//item的类型通过C#编译器推断得知是int
{
Console.WriteLine(i);
}
//var x; // 错误,没有用来推断类型的初始化器
//var y = { 1, 2, 3 }; // 错误,不允许使用集合初始化器
//var z = null; // 错误,不允许出现空类型
}
本质:
var并非动态类型,C#仍然是静态语言,引入var方便我们写代码了,可以不管“=”后面的赋值表达式类型了,由编译器自己去推断生成对应类型了。
对Linq的意义:
可以自动推断出Linq查询返回的集合类型。
4、匿名类型
private static void AnonymousType()
{
/ /无须显示声明一个类,而且在初始化器里面可以获取上下文的变量——闭包
var v = new { Name = "张三", Sex = true };
Console.WriteLine(v.Name);
}
本质:
有了匿名类型后我们不需要显示的声明一个类型了,这个类型由C#编译器自动生成,而且利用了初始化器和var的新特性.
对Linq的意义:
和初始化器结合起来构造查询结果集合里面的新元素类型。
5、扩展方法
比如我们现在想给int类型增加(扩展)一个方法,判断一个整数自身是否偶数,我们期望的语法是这样的:
private static void ExtendMethod()
{
int i = 2;
Console.WriteLine(i.IsEven());
}
注意原来int原来是没有IsEven()这个方法的,要实现这个方法,必须写一个静态类和一个静态方法。
static class MyExtention
{
//this 表示针对int的实例和索引器的this的含义是一样的,int表示给int这种类型进行扩展
public static bool IsEven(this int num)
{
return num % 2 == 0;
}
}
本质:
编译i.IsEven()的本质是C#编译器生成了了MyExtention.IsEven(i)的代码,实际上仍然没有破坏类型的结构,并不是真的象语法那样平白无故给int增加了一个IsEven()方法,和设计模式里面的Visitor模式动态注入方法还是有区别的。
对Linq的意义:
用来对集合类型扩展不同的查询方法。
6、Lambda表达式和Linq查询
接下来我们通过一个例子来看一下Lambda表达式和Linq查询的关系:
我们现在想给ClassCollection增加一个过滤方法,方法的目的是能够过滤返回班级名称为“终极一班”的集合来。
这也就是我们所说的Lambda表达式了:
private static void LambdaLinq()
{
var classes = GetClasses();
string className = "终极一班";
// C#3.0 Lambda表达式
var result = classes.Filter(c=> c.Name == className);
foreach (var item in result)
{
Console.WriteLine(item.ID+ " " + item.Name);
}
}
“=>”左边的就是我们上面匿名方法的参数列表,右边的是方法里,实际上lambda表达式也可以写成如下形式:
Class c => c.Name == className
(Class c) => c.Name == className
(Class c) => {return c.Name == className;}
(x,y)=> x+y;//多参数
等等,函数的返回类型也是由编译器根据"=>"右边的表达式自动推断出来的。
而且需要提到的是由于Filter是扩展方法的缘故,而且Filter方法返回类型是ClassCollection,所以可以无限扩展下去,例如
varresult=classes.Filter(c=>c.Name==className).Filter(c=>c.ID>1);
这就是扩展方法的魅力所在!
实际上不知不觉,我们已经实现了Linq里面的一个Where功能了
我们现在导入命名空间
using System.Linq;
然后会发现classes这个实例会增加了很多扩展方法例如Where,OrderBy,这些方法实际上就是一些给实现了IEnumerable接口的类型的扩展方法,说白了就是针对集合类型的一些相关方法,比如过滤、排序、合并、分组等方法,这些方法的返回类型依然是IEnumerable,当然这些方法都离不开我们的Lambda表达式做参数。
private static void LambdaLinq()
{
var classes = GetClasses();
string className = "终极一班";
// C#3.0里面的Where扩展方法(专门给实现了IEnumerable接口的类做扩展)
var result = classes.Where(c => c.Name == className);
foreach (var item in result)
{
Console.WriteLine(item.ID+ " " + item.Name);
}
}
我们还可以这样可以无限扩展下去:
varresult=classes.Where(c=>c.Name==className).OrderBy(c=>c.ID);
这样写针对IEnumarable类型的查询其实已经不错了,微软觉得还不过瘾,又提供了我们传说中的Linq查询表达式.
private static void LambdaLinq()
{
var classes = GetClasses();
string className = "终极一班";
// Linq查询表达式
var result = from c in classes where c.Name==className orderby c.ID select c;
foreach (var item in result)
{
Console.WriteLine(item.ID+" "+item.Name);
}
}
其实它的本质都是面向对象的一些东西,并没有创造出一些什么新的东西来,这样我们才可以真正理解语言。
最后一个稍微复杂一些的Linq查询,就是班级和学生结合的一个连接,连接的条件是班级的id和学生的所属班级id,然后生成一个新的集合,这个集合里面的元素成员包括班级名称和学生名称。
涉及到的相关类如下:
class Student
{
public int ID { get; set; }
public string Name { get; set; }
public int ClassID { get; set; }
}
class StudentCollection :
List
{
}
获取学生集合的工厂方法:
static StudentCollection GetStudents()
{
return new StudentCollection()
{
new Student { ID=1,Name="大东", ClassID=1},
new Student{ID=2,Name="亚瑟",ClassID=1},
new Student { ID=3,Name="小雨", ClassID=1},
new Student{ID=4,Name="雷克斯",ClassID=1},
new Student{ID=2,Name="张三",ClassID=2},
new Student { ID=3,Name="李四", ClassID=2},
new Student{ID=4,Name="王二麻子",ClassID=2}
};
}
private static void LambdaLinq()
{
var classes = GetClasses();
var students=GetStudents();
// Linq查询表达式 Join
var result = from c in classes
join s in students on c.ID equals s.ClassID
select new { ClassName = c.Name, StudentName = s.Name };//匿名类型和初始化器新特性的使用
//var result = classes.Join(students,c=>c.ID,s=>s.ClassID,(c,s)=>new {ClassName=c.Name,StudentName=s.Name}
foreach (var item in result)
{
//注意元素的属性成员已经改变
Console.WriteLine(item.ClassName + " " + item.StudentName);
}
}
三、LinqToSql集成数据库语言的优劣
1、LinqToSql的优点
在LinqToSql推出之前,我们只是把sql语句形成一个string,然后,通过传给sqlserver,返回结果集.这里的缺陷就是,如果你sql语句写的有问题,只有到运行时才知道.而且并不所有的人都懂数据库的。
LinqToSQL在一切围绕数据的项目内都可以使用。
特别是在项目中缺少SQLServer方面的专家时,LinqToSQl的强大的功能可以帮我们快速的完成项目。
LinqToSQL的推出,是让大家从烦琐的技术细节中解脱出来,更加关注项目的逻辑。
LinqToSql的出现,大大降低了数据库应用程序开发的门槛,它实质是事先为你构架了数据访问层,势必将加快数据库应用程序的开发进度。
LinqToSql解放了众多程序员,让他们的把更多的精力放到业务逻辑以及code上,而不是数据库。
对于初学者来讲,LinqToSql可以让他们迅速进入数据库应用程序开发领域,节约了培训成本。
LinqToSQl的实现,是在和C#2.0的基础上的。
它通过自动翻译sql语句,并把结果集创建成对象并返回。
这里我们可以看出,发送到SQLServer端的sql语句是LinqToSql自动生成的。
这对不懂sql的人来说,无疑是个福音。
第二,LinqToSql语句是在编译期间就做检查的。
而不是运行时检查。
这样,那里出了问题,可以及时更改,而不是到了运行时才发现问题。
第三,LinqToSql是针对对象操作的,更符合今天的oo呼声。
在LinqToSQL之前,在Java领域有Hibernate,在net领域有NHibernate技术,来实现object/relational持久和查询服务。
那和NHibernate比起来,它又有那些优势呢.第一,影射代码自动生成。
VS2008提供了SqlMetal和ORDesigner两个工具来完成此步骤。
而在NHibernate中,你不得不自己手工写。
第二,影射代码有更多的选择.NHibernate只能把数据库的信息配置在一个xml中,而LinqToSql有两种方式,一个是放到XML中,我们称为ExternlMapping,再一种就是以Attribute的形式,存在于各个property中。
2、LinqToSql的缺点
LinqToSql在动态构造语句时,比拼接sql麻烦很多。
在LinqToSql进阶系列动态查询中推荐使用object的查询。
这符合LinqToSql的设计原则。
因为,它主要是为了解决data!
=objects的问题而产生的.它所有的操作均针对object,那就让我们使用object的查询吧。
当然,依然会有人习惯拼接字符串.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linq 技术研究