LINQ中文教程.docx
《LINQ中文教程.docx》由会员分享,可在线阅读,更多相关《LINQ中文教程.docx(105页珍藏版)》请在冰豆网上搜索。
LINQ中文教程
LINQ中文教程
目录
1初体验之LINQtoObject-1-
2一步一步学Linqtosql-4-
2.1预备知识-4-
2.1.1隐含类型局部变量-4-
2.1.2匿名类型-4-
2.1.3扩展方法-5-
2.1.4自动属性-6-
2.1.5对象初始化器-6-
2.1.6集合初始化器-7-
2.1.7Lambda表达式-7-
2.1.8查询句法-8-
2.2DataContext与实体-9-
2.2.1定义实体类-10-
2.2.2强类型DataContext-11-
2.2.3日志功能-12-
2.2.4探究查询-12-
2.2.5执行查询-13-
2.2.6创建数据库-14-
2.2.7使用DbDataReader数据源-15-
2.3增删改-16-
2.3.1示例数据库-16-
2.3.2生成实体类-16-
2.3.3简易留言簿-17-
2.4查询句法-24-
2.4.1select-24-
2.4.2where-27-
2.4.3orderby-28-
2.4.4分页-29-
2.4.5分组-30-
2.4.6distinct-32-
2.4.7union-33-
2.4.8concat-34-
2.4.9取相交项-35-
2.4.10排除相交项-36-
2.4.11子查询-37-
2.4.12in操作-38-
2.4.13join-39-
2.5储过程-40-
2.5.1普通存储过程-40-
2.5.2带参数的存储过程-42-
2.5.3带返回值的存储过程-43-
2.5.4多结果集的存储过程-44-
2.5.5使用存储过程新增数据-45-
2.5.6使用存储过程删除数据-47-
2.5.7使用存储过程更改数据-48-
2.6探究特性-50-
2.6.1延迟执行-50-
2.6.2主键缓存-57-
2.6.3DataContext隔离-58-
2.7并发与事务-59-
2.7.1检测并发-59-
2.7.2解决并发-60-
2.7.3事务处理-64-
2.8继承与关系-66-
2.8.1论坛表结构-66-
2.8.2实体继承的定义-67-
2.8.3实体继承的使用-69-
2.8.4实体关系的定义-71-
2.8.5实体关系的使用-73-
2.9其它补充-77-
2.9.1外部映射文件-77-
2.9.2处理空值-77-
2.9.3已编译查询-78-
2.9.4撤销提交-79-
2.9.5批量操作-80-
2.10分层构架的例子-80-
2.10.1项目介绍-80-
2.10.2生成映射文件和实体-81-
2.10.3编写数据访问服务-81-
2.10.4WCF服务端与客户端-84-
2.10.5调用服务-86-
3学习LinqToXml-89-
3.1概述-89-
3.1.1直接使用XML元素-90-
3.1.2命名空间-91-
3.2编程概述-92-
3.2.1类概述-92-
3.2.2XDocument类概述-94-
3.2.3XElement类概述-96-
3.3Linq操作XML-98-
3.3.1编程创建XML文档-98-
3.3.2查询创建XML文档-99-
3.3.3加载和解析XML内容-100-
3.3.4遍历内存中的XML文档-100-
3.3.5修改XML文档-102-
1初体验之LINQtoObject
VS2008的发布,最激动人心的莫过是LINQ的诞生。
What‘sLINQ?
LanguageIntegratedQuery是也。
说得再明白一些,这是编程语言的一种新特性,能够将数据查询语句集成到编程语言中。
目前,支持LINQ的语言有C#和VB。
为啥会有LINQ,主要还是因为现在的数据格式越来越多,数据库、XML、数组、哈希表……每一种都有自己操作数据的方式,学起来费事费力。
于是,就有了LINQ诞生的理由——以一种统一的方式操作各种数据源,减少数据访问的复杂性。
LINQ带来很多开发上的便利。
首先,他可以利用VisualStudio这个强大的IDE(这话决不是吹,VisualStudio绝对是最好用的开发工具之一),至少用VisualStudio来写SQL语句,可以有智能感知了,比起从前用查询分析器写存储过程的感觉好多了!
其次,它可以把数据当成一个对象来操作,即Data==Object?
的问题。
LINQ目前可以对XML,Object,SQL做数据访问,今后还会有LINQtoEntity的功能。
说来惭愧,我也是刚刚才接触LINQ,先从最简单的开始吧,做一个LINQtoObject的例子,实现一个对数组的操作。
这个例子套用了今年TechED中海洋兄讲的例子,在此声明。
在这个例子中,我会先通过GetMethods的方法,拿到string的所有方法,接下来,就看LINQ的厉害了,这里是选出所有非静态的方法签名。
MethodInfo[] methods = typeof(string).GetMethods();
var result = from m in methods
where m.IsStatic !
=true
select m.Name;
foreach (var r in result)
{
Console.WriteLine(r.ToString());
}
Console.ReadLine();
例子虽然简单,确能从中看出LINQ的一些端倪。
首先,var是什么东东?
看起来,有点像javascript里面的弱类型的变量声明。
但是,C#是强类型的,尽管你用var来声明,编译器还是可以根据上下文推倒出它当前的类型。
比如这个例子里面,result就是IEnumerable类型的。
在这里面,写IEnumerable和写var是一样效果的,显然,var会简单得多。
你不用考虑数据操作的返回值是什么类型,还能享受强类型声明带来的方便实惠……
还有fromminmethods这句,m是什么东西,m是隐式声明的一个变量,尽管没有声明,但编译器根据上下文,推断出它的类型是MethodInfo型的!
.NETFramework3.5的编译器的确是聪明了很多^^。
上面这个例子运行起来的结果中有很多重复的记录,我们可以用distinct()来过滤掉重复的,和SQL还是很相似的说。
var result = (from m in methods
where m.IsStatic !
=true
select m.Name).Distinct();
或者用groupby也可以
var result = from m in methods
where m.IsStatic !
=true
group m by m.Name;
但是这样子写,在输出的时候,显示的是System.Linq.Lookup`2+Grouping[System.String,System.Reflection.MethodInfo],所以,再做一些修改
var result = from m in methods
where m.IsStatic !
=true
group m by m.Name into g
select new { MethodName = g.Key, Overload = g.Count() };
这里面又有一些新鲜的了——selectnew{MethodName=g.Key,Overload=g.Count()},先来看一个简单一些的例子:
class MyClass
{
public string MethodName { get; set; }
public int Overload { get; set; }
}
class Program
{
MyClass mc = new MyClass { MethodName = "aaa", Overload = 2 };
}
大括号里面的叫类初始化器,省去了构造函数,在new的同时,给对象的属性赋值。
这时候再回来看看selectnew{MethodName=g.Key,Overload=g.Count()},跟这个类初始化器很像吧,但是它更偷懒,new一个新对象,居然连类名都不写。
没错,这就叫匿名类。
不用写类的声明,直接实例化。
类的名字是由编译器在编译的时候自动生成的,也就是说,你在new的时候根本不知道这个类叫啥名,因此,这里就只能用var了。
这就更看出var的厉害了,不仅仅是写起来方便这么简单,在用到匿名类的时候,没有类名,这时候只能用var,嘿嘿!
2一步一步学Linqtosql
2007-08-24作者:
lovecherry出处:
天极网
2.1预备知识
什么是Linqtosql?
Linqtosql(或者叫DLINQ)是LINQ(.NET语言集成查询)的一部分,全称基于关系数据的.NET语言集成查询,用于以对象形式管理关系数据,并提供了丰富的查询功能,它和Linqtoxml、Linqtoobjects、Linqtodataset、Linqtoentities等组成了强大的LINQ。
要学好LINQ查询语法,就不得不先理解C#3.0的一些新特性,下面一一简单介绍。
2.1.1隐含类型局部变量
var age = 26;
var username = "zhuye";
var userlist = new [] {"a","b","c"};
foreach(var user in userlist)
Console.WriteLine(user);
纯粹给懒人用的var关键字,告诉编译器(对于CLR来说,它是不会知道你是否使用了var,苦力是编译器出的),你自己推断它的类型吧,我不管了。
但是既然让编译器推断类型就必须声明的时候赋值,而且不能是null值。
注意,这只能用于局部变量,用于字段是不可以的。
2.1.2匿名类型
var data = new {username = "zhuye",age = 26};
Console.WriteLine("username:
{0} age:
{1}", data.username, data.age);
匿名类型允许开发人员定义行内类型,无须显式定义类型。
常和var配合使用,var用于声明匿名类型。
定义一个临时的匿名类型在LINQ查询句法中非常常见,我们可以很方便的实现对象的转换和投影。
2.1.3扩展方法
public static class helper
{
public static string MD5Hash(this string s)
{
return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(s,"MD5");
}
public static bool In(this object o, IEnumerable b)
{
foreach(object obj in b)
{
if(obj==o)
return true;
}
return false;
}
}
// 调用扩展方法
Console.WriteLine("123456".MD5Hash());
Console.WriteLine("1".In(new[]{"1","2","3"}));
很多时候我们需要对CLR类型进行一些操作,苦于无法扩展CLR类型的方法,只能创建一些helper方法,或者生成子类。
扩展方法使得这些需求得以实现,同时也是实现LINQ的基础。
定义扩展方法需要注意,只能在静态类中定义并且是静态方法,如果扩展方法名和原有方法名发生冲突,那么扩展方法将失效。
2.1.4自动属性
public class Person
{
public string username { get; protected set; }
public int age { get; set; }
public Person()
{
this.username = "zhuye";
}
}
Person p = new Person();
//p.username = "aa";
Console.WriteLine(p.username);
意义不是很大,纯粹解决机械劳动。
编译器自动为你生成get、set操作以及字段,并且你不能使用字段也不能自定义get、set操作,不过你可以分别定义get和set的访问级别。
2.1.5对象初始化器
public class Person
{
public string username { get; set; }
public int age { get; set; }
public override string ToString()
{
return string.Format("username:
{0} age:
{1}", this.username, this.age);
}
}
Person p = new Person() {username = "zhuye", age=26};
Console.WriteLine(p.ToString());
编译器会自动为你做setter操作,使得原本几行的属性赋值操作能在一行中完成。
这里需要注意:
●允许只给一部分属性赋值,包括internal访问级别
●可以结合构造函数一起使用,并且构造函数初始化先于对象初始化器执行
2.1.6集合初始化器
public class Person
{
public string username { get; set; }
public int age { get; set; }
public override string ToString()
{
return string.Format("username:
{0} age:
{1}", this.username, this.age);
}
}
var persons = new List {
new Person {username = "a", age=1},
new Person {username = "b", age=2}};
foreach(var p in persons)
Console.WriteLine(p.ToString());
编译器会自动为你做集合插入操作。
如果你为Hashtable初始化的话就相当于使用了两个对象初始化器。
2.1.7Lambda表达式
var list = new [] { "aa", "bb", "ac" };
var result = Array.FindAll(list, s => (s.IndexOf("a") > -1));
foreach (var v in result)
Console.WriteLine(v);
其实和2.0中的匿名方法差不多,都是用于产生内联方法,只不过Lambda表达式的语法更为简洁。
语法如下:
●(参数列表)=>表达式或者语句块
●其中:
⏹参数个数:
可以有多个参数,一个参数,或者无参数。
⏹表达式或者语句块:
这部分就是我们平常写函数的实现部分(函数体)。
前面的示例分别是1个参数的例子,下面结合扩展方法来一个复杂的例子:
public delegate int mydg(int a, int b);
public static class LambdaTest
{
public static int oper(this int a, int b, mydg dg)
{
return dg(a, b);
}
}
Console.WriteLine(1.oper(2, (a, b) => a + b));
Console.WriteLine(2.oper(1, (a, b) => a - b));
2.1.8查询句法
var persons = new List {
new Person {username = "a", age=19},
new Person {username = "b", age=20},
new Person {username = "a", age=21},
};
var selectperson = from p in persons where p.age >= 20 select p.username.ToUpper();
foreach(var p in selectperson)
Console.WriteLine(p);
查询句法是使用标准的LINQ查询运算符来表达查询时一个方便的声明式简化写法。
该句法能在代码里表达查询时增进可读性和简洁性,读起来容易,也容易让人写对。
VisualStudio对查询句法提供了完整的智能感应和编译时检查支持。
编译器在底层把查询句法的表达式翻译成明确的方法调用代码,代码通过新的扩展方法和Lambda表达式语言特性来实现。
上面的查询句法等价于下面的代码:
var selectperson = persons.Where(p=>p.age>=20).Select(p=>p.username.ToUpper());
LINQ查询句法可以实现90%以上T-SQL的功能(由于T-SQL是基于二维表的,所以LINQ的查询语法会比T-SQL更简单和灵活),但是由于智能感应的原因,select不能放在一开始就输入。
2.2DataContext与实体
DataContext类型(数据上下文)是System.Data.Linq命名空间下的重要类型,用于把查询句法翻译成SQL语句,以及把数据从数据库返回给调用方和把实体的修改写入数据库。
DataContext提供了以下一些使用的功能:
●以日志形式记录DataContext生成的SQL
●执行SQL(包括查询和更新语句)
●创建和删除数据库
DataContext是实体和数据库之间的桥梁,那么首先我们需要定义映射到数据表的实体。
2.2.1定义实体类
using System.Data.Linq.Mapping;
[Table(Name = "Customers")]
public class Customer
{
[Column(IsPrimaryKey = true)]
public string CustomerID {get; set;}
[Column(Name = "ContactName")]
public string Name { get; set; }
[Column]
public string City {get; set;}
}
以Northwind数据库为例,上述Customers类被映射成一个表,对应数据库中的Customers表。
然后在类型中定义了三个属性,对应表中的三个字段。
其中,CustomerID字段是主键,如果没有指定Column特性的Name属性,那么系统会把属性名作为数据表的字段名,也就是说实体类的属性名就需要和数据表中的字段名一致。
现在,创建一个ASP.NET页面,然后在页面上加入一个GridView控件,使用下面的代码进行绑定数据:
using System.Data.Linq;
DataContext ctx = new DataContext("server=xxx;database=Northwind;uid=xxx;pwd=xxx");
Table Customers = ctx.GetTable();
GridView1.DataSource = from c in Customers where c.CustomerID.StartsWith("A") select new {顾客ID=c.CustomerID, 顾客名=c.Name, 城市=c.City};
GridView1.DataBind();
使用DataContext类型把实体类和数据库中的数据进行关联。
你可以直接在DataContext的构造方法中定义连接字符串,也可以使用IDbConnection:
using System.Data.SqlClient;
IDbConnection conn = new SqlConnection("server=xxx;database=Northwind;uid=xxx;pwd=xxx");
DataContext ctx = new DataContext(conn);
之后,通过GetTable获取表示底层数据表的Table类型,显然,数据库中的Customers表的实体是Customer类型。
随后的查询句法,即使你不懂SQL应该也能看明白。
从Customers表中找出CustomerID以“A”开头的记录,并把CustomersID、Name以及City封装成新的匿名类型进行返回。
结果如下图:
2.2.2强类型DataContext
public partial class NorthwindDataContext :
DataContext
{
public Table Customers;
public NorthwindDataContext(IDbConnection connection) :
base(connection) { }
public NorthwindDataContext(string connection) :
base(connection) { }
}
强类型数据上下文使代码更简洁:
NorthwindDataContext ctx = new NorthwindDataContext("server=xxx;database=Northwind;uid=xxx;pwd=xxx");
GridView1.DataSource = from c in ctx.Customers where c.CustomerID.StartsWith("A") select new { 顾客ID = c.CustomerID, 顾客名 = c.Name, 城市 = c.City };
GridV