LINQ

更新时间:2024-06-02 19:12:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

LINQ初体验之LINQ to Object ...................................................................................................... 1

一步一步学Linq to sql(一):预备知识............................................................................. 4 一步一步学Linq to sql(二):DataContext与实体 ........................................................... 9 一步一步学Linq to sql(三):增删改 .............................................................................. 15 一步一步学Linq to sql(四):查询句法........................................................................... 21 一步一步学Linq to sql(五):存储过程........................................................................... 35 一步一步学Linq to sql(六):探究特性........................................................................... 46 一步一步学Linq to sql(七):并发与事务....................................................................... 53 一步一步学Linq to sql(八):继承与关系....................................................................... 60 一步一步学Linq to sql(九):其它补充........................................................................... 69 一步一步学Linq to sql(十):分层构架的例子 ............................................................... 73 Linq To Xml学习 ........................................................................................................................... 80

Linq To Xml学习 - 1. 概述 .............................................................................................. 80 Linq To Xml学习 - 2 编程概述 ....................................................................................... 82 C# 2008 学习笔记 - LINQ to XML ............................................................................................. 87

一、命名空间 ......................................................................................................................... 87 二、编程方式创建XML文档 .............................................................................................. 88 三、使用 LINQ 查询创建XML文档 ................................................................................ 89 四、加载和解析XML内容 .................................................................................................. 90 六、遍历内存中的XML文档 .............................................................................................. 90 七、修改 XML文档 ............................................................................................................. 92 使用linq to xml 快速创建自己的Rss ........................................................................................ 93

LINQ初体验之LINQ to Object

VS2008的发布,最激动人心的不过是LINQ的诞生。

What‘s LINQ? Language Integrated Query 是也。说得再明白一些,这是编程语言的一种新特性,能够将数据查询语句集成到编程语言中。目前,LINQ支持的语言有C# 和 VB。

为啥会有LINQ,主要还是因为现在的数据格式越来越多,数据库、XML、数组、哈希表……每一种都有自己操作数据的方式,学起来费事费力。于是,就有了LINQ诞生的理由——以一种统一的方式操作各种数据源,减少数据访问的复杂性。

LINQ带来很多开发上的便利。首先,他可以利用Visual Studio这个强大的IDE(这话决不是吹,Visual Studio绝对是最好用的开发工具之一),至少用Visual Studio来写SQL语句,可以有智能感知了,比起从前用查询分析器写存储过程的感觉好多了!其次,它可以把数据当成一个对象来操作,即 Data == Object? 的问题。

LINQ目前可以对XML, Object, SQL做数据访问,今后还会有LINQ to Entity的功能。

说来惭愧,我也是刚刚才接触LINQ,先从最简单的开始吧,做一个LINQ to Object的例子,实现一个对数组的操作。这个例子套用了今年TechED中海洋兄讲的例子,在此声明。

在这个例子中,我会先通过GetMethods的方法,拿到string的所有方法,接下来,就看LINQ的厉害了,这里是选出所有非静态的方法签名。 (var 可以根据上下文来判定你是什么类型)

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会简单得多。你不用考虑数据操作的返回值是什么类型,还能享受强类型声明带来的方便实惠……

还有from m in methods这句,m是什么东西,m是隐式声明的一个变量,尽管没有声明,但编译器根据上下文,推断出它的类型是MethodInfo型的!.NET Framework 3.5的编译器的确是聪明了很多 ^^

上面这个例子运行起来的结果中有很多重复的记录,我们可以用distinct()来过滤掉重复的,和SQL还是很相似的说。

var result = (from m in methods where m.IsStatic != true select m.Name).Distinct(); 或者用group by 也可以

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() };

这里面又有一些新鲜的了——select new { 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 = \ }

大括号里面的叫类初始化器,省去了构造函数,在new的同时,给对象的属性赋值。

这时候再回来看看select new { MethodName = g.Key, Overload = g.Count() },跟这个类初始化器很像吧,但是它更偷懒,new一个新对象,居然连类名都不写。没错,这就叫匿名类。不用写类的声明,直接实例化。类的名字是由编译器在编译的时候自动生成的,也就是说,你在new的时候根本不知道这个类叫啥名,因此,这里就只能用var了。这就更看出var的厉害了,不仅仅是写起来方便这么简单,在用到匿名类的时候,没有类名,这时候只能用var,嘿嘿!

一步一步学Linq to sql(一):预备知识

2007-08-14 09:00 作者: lovecherry 出处: 天极网 责任编辑:>dizzarz 什么是Linq to sql

Linq to sql(或者叫DLINQ)是LINQ(.NET语言集成查询)的一部分,全称基于关系数据的 .NET 语言集成查询,用于以对象形式管理关系数据,并提供了丰富的查询功能,它和Linq to xml、Linq to objects、Linq to dataset、Linq to entities等组成了强大的LINQ。

要学好LINQ查询语法,就不得不先理解C# 3.0的一些新特性,下面一一简单介绍。

隐含类型局部变量

用var 定义隐含的局部变量个匿名类

var age = 26;

var username = \

var userlist = new [] {\

foreach(var user in userlist) Console.WriteLine(user);

纯粹给懒人用的var关键字,告诉编译器(对于CLR来说,它是不会知道你是否使用了var,苦力是编译器出的),你自己推断它的类型吧,我不管了。但是既然让编译器推断类型就必须声明的时候赋值,而且不能是null值。注意,这只能用于局部变量,用于字段是不可以的。 匿名类型

var data = new {username = \

Console.WriteLine(\ 匿名类型允许开发人员定义行内类型,无须显式定义类型。常和var配合使用,var用于声明匿名类型。定义一个临时的匿名类型在LINQ查询句法中非常常见,我们可以很方便的实现对象的转换和投影。

扩展方法

在静态类中定义静态的方法

public static class helper {

public static string MD5Hash(this string s) {

return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(s,\ }

public static bool In(this object o, IEnumerable b) {

foreach(object obj in b) {

if(obj==o) return true; }

return false; }

}

// 调用扩展方法

Console.WriteLine(\ Console.WriteLine(\

很多时候我们需要对CLR类型进行一些操作,苦于无法扩展CLR类型的方法,只能创建一些helper方法,或者生成子类。扩展方法使得这些需求得意实现,同时也是实现LINQ的基础。定义扩展方法需要注意,只能在静态类中定义并且是静态方法,如果扩展方法名和原有方法名发生冲突,那么扩展方法将失效。 自动属性

编译器会自动的为你做set的赋值操作

public class Person {

public string username { get; protected set; } public int age { get; set; } public Person() {

this.username = \ } }

Person p = new Person(); //p.username = \

Console.WriteLine(p.username);

意义不是很大,纯粹解决机械劳动。编译器自动为你生成get、set操作以及字段,并且你不能使用字段也不能自定义get、set操作,不过你可以分别定义get和set的访问级别。 对象初始化器

public class Person {

public string username { get; set; } public int age { get; set; }

public override string ToString() {

return string.Format(\ } }

Person p = new Person() {username = \ Console.WriteLine(p.ToString());

编译器会自动为你做setter操作,使得原本几行的属性赋值操作能在一行中完成。这里需要注意:

? ?

允许只给一部分属性赋值,包括internal访问级别 可以结合构造函数一起使用,并且构造函数初始化先于对象初始化器执行

集合初始化器

public class Person {

public string username { get; set; } public int age { get; set; }

public override string ToString() {

return string.Format(\ } }

var persons = new List {

new Person {username = \ new Person {username = \ foreach(var p in persons)

Console.WriteLine(p.ToString());

编译器会自动为你做集合插入操作。如果你为Hashtable初始化的话就相当于使用了两个对象初始化器。 Lambda表达式 是经过委托演变过来的

var list = new [] { \

var result = Array.FindAll(list, s => (s.IndexOf(\

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)); 查询句法

显示满足的条件,然后是查询的结果

var persons = new List {

new Person {username = \ new Person {username = \ new Person {username = \ };

var selectperson = from p in persons where p.age >= 20 select p.username.ToUpper(); foreach(var p in selectperson) Console.WriteLine(p);

查询句法是使用标准的LINQ查询运算符来表达查询时一个方便的声明式简化写法。该句法能在代码里表达查询时增进可读性和简洁性,读起来容易,也容易让人写对。Visual Studio 对查询句法提供了完整的智能感应和编译时检查支持。编译器在底层把查询句法的表达式翻译成明确的方法调用代码,代码通过新的扩展方法和Lambda表达式语言特性来实现。上面的查询句法等价于下面的代码:

var selectperson = persons.Where(p=>p.age>=20).Select(p=>p.username.ToUpper()); LINQ查询句法可以实现90%以上T-SQL的功能(由于T-SQL是基于二维表的,所以LINQ的查询语法会比T-SQL更简单和灵活),但是由于智能感应的原因,select不能放在一开始就输入。

一步一步学Linq to sql(二):DataContext与实体

2007-08-24 00:00 作者: LoveCherry 出处: 天极网 责任编辑:>dizzarz DataContext

DataContext类型(数据上下文)是System.Data.Linq命名空间下的重要类型,用于把查询句法翻译成SQL语句,以及把数据从数据库返回给调用方和把实体的修改写入数据库。

DataContext提供了以下一些使用的功能: 以日志形式记录DataContext生成的SQL 执行SQL(包括查询和更新语句) 创建和删除数据库

DataContext是实体和数据库之间的桥梁,那么首先我们需要定义映射到数据表的实体。

定义实体类

using System.Data.Linq.Mapping;

[Table(Name = \ public class Customer {

[Column(IsPrimaryKey = true)] public string CustomerID {get; set;}

[Column(Name = \ 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(\ Table Customers = ctx.GetTable();

GridView1.DataSource = from c in Customers where c.CustomerID.StartsWith(\顾客ID=c.CustomerID, 顾客名=c.Name, 城市=c.City}; GridView1.DataBind();

使用DataContext类型把实体类和数据库中的数据进行关联。你可以直接在DataContext的构造方法中定义连接字符串,也可以使用IDbConnection:

using System.Data.SqlClient;

IDbConnection conn = new SqlConnection(\ DataContext ctx = new DataContext(conn);

之后,通过GetTable获取表示底层数据表的Table类型,显然,数据库中的Customers表的实体是Customer类型。随后的查询句法,即使你不懂SQL应该也能看明白。从Customers表中找出CustomerID以“A”开头的记录,并把CustomersID、Name以及City封装成新的匿名类型进行返回。 结果如下图:

强类型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(\ GridView1.DataSource = from c in ctx.Customers where c.CustomerID.StartsWith(\顾客ID = c.CustomerID, 顾客名 = c.Name, 城市 = c.City }; GridView1.DataBind();

DataContext其实封装了很多实用的功能,下面一一介绍。

日志功能

using System.IO;

NorthwindDataContext ctx = new NorthwindDataContext(\ StreamWriter sw = new StreamWriter(Server.MapPath(\ ctx.Log = sw;

GridView1.DataSource = from c in ctx.Customers where c.CustomerID.StartsWith(\顾客ID = c.CustomerID, 顾客名 = c.Name, 城市 = c.City }; GridView1.DataBind(); sw.Close();

运行程序后在网站所在目录生成了log.txt,每次查询都会把诸如下面的日志追加到文本文件中:

SELECT [t0].[CustomerID], [t0].[ContactName], [t0].[City] FROM [Customers] AS [t0]

WHERE [t0].[CustomerID] LIKE @p0

-- @p0: Input String (Size = 2; Prec = 0; Scale = 0) [A%]

-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1 应该说这样的日志对于调试程序是非常有帮助的。

探究查询

using System.Data.Common;

using System.Collections.Generic;

NorthwindDataContext ctx = new NorthwindDataContext(\ var select = from c in ctx.Customers where c.CustomerID.StartsWith(\顾客ID = c.CustomerID, 顾客名 = c.Name, 城市 = c.City }; DbCommand cmd = ctx.GetCommand(select); Response.Write(cmd.CommandText + \ foreach (DbParameter parm in cmd.Parameters)

Response.Write(string.Format(\参数名:{0},参数值:{1}
\ Customer customer = ctx.Customers.First(); customer.Name = \

IList queryText = ctx.GetChangeSet().ModifiedEntities; Response.Write(((Customer)queryText[0]).Name);

在这里,我们通过DataContext的GetCommand方法获取了查询对应的DbCommand,并且输出了CommandText和所有的DbParameter。之后,我们又通过GetChangeSet方法获取了修改后的实体,并输出了修改内容。

执行查询

orthwindDataContext ctx = new NorthwindDataContext(\ ring newcity = \

x.ExecuteCommand(\

Enumerable customers = ctx.ExecuteQuery(\ridView1.DataSource = customers; ridView1.DataBind();

前一篇文章已经说了,虽然Linq to sql能实现90%以上的TSQL功能。但是不可否认,对于复杂的查询,使用TSQL能获得更好的效率。因此,DataContext类型也提供了执行SQL语句的能力。代码的执行结果如下图:

创建数据库 testContext ctx = new testContext(\ ctx.CreateDatabase(); [Table(Name = \ public class test { [Column(IsPrimaryKey = true, IsDbGenerated = true)] public int ID { get; set; } [Column(DbType=\ public string Name { get; set; } } public partial class testContext : DataContext { public Table test; public testContext(string connection) : base(connection) { } } testContext ctx = new testContext(\ctx.CreateDatabase(); [Table(Name = \public class test { [Column(IsPrimaryKey = true, IsDbGenerated = true)] public int ID { get; set; } [Column(DbType=\ public string Name { get; set; } } public partial class testContext : DataContext { public Table test; public testContext(string connection) : base(connection) { } } 这段代码在数据库中创建了名为testdb的数据库,等同于下面的脚本:

CREATE TABLE [dbo].[test](

[ID] [int] IDENTITY(1,1) NOT NULL,

[Name] [varchar](20) COLLATE Chinese_PRC_CI_AS NULL, CONSTRAINT [PK_test] PRIMARY KEY CLUSTERED (

[ID] ASC

)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY]

同时,DataContext还提供了DeleteDatabase()方法,在这里就不列举了。

使用DbDataReader数据源

using System.Data.SqlClient;

var conn = new SqlConnection(\ var ctx = new DataContext(conn);

var cmd = new SqlCommand(\ conn.Open();

var reader = cmd.ExecuteReader();

GridView1.DataSource = ctx.Translate(reader); GridView1.DataBind(); conn.Close();

你同样可以选择使用DataReader获取数据,增加了灵活性的同时也增加了性能。

看到这里,你可能会觉得手工定义和数据库中表对应的实体类很麻烦,不用担心,VS2008提供了自动生成实体类以及关系的工具,工具的使用将在以后讲解。今

天就讲到这里,和DataContext相关的事务、加载选项、并发选项以及关系实体等高级内容也将在以后讲解。

一步一步学Linq to sql(三):增删改

2007-10-20 00:00 作者: lovecherry 出处: 天极网 责任编辑:>dizzarz 示例数据库 字段名 字段类型 允许空 字段说明 ID uniqueidentifier 表主键字段 UserName varchar(50) 留言用户名 PostTime datetime 留言时间 Message varchar(400) √ 留言内容 IsReplied bit 留言是否回复 Reply varchar(400) √ 留言管理员回复 在数据库中创建一个名为GuestBook的数据库,在里面创建一个tbGuestBook的表,结构如上表。

生成实体类

右键点击网站项目,选择添加新项,然后选择“Linq to sql Classes”,命名为GuestBook。然后打开App_Code里面的GuestBook.dbml。设计视图上的文字提示你可以从服务器资源管理器或者攻击箱拖动项到设计界面上来创建实体类。 那么,我们就在服务器资源管理器中创建一个指向GuestBook数据库的数据连接,然后把tbGuestBook表拖动到GuestBook.dbml的设计视图上,按CTRL+S保存。打开GuestBook.designer.cs可以发现系统自动创建了GuestBook数据库中tbGuestBook表的映射,如下图:

简易留言簿

现在,我们就可以使用Linq to sql完成简易留言簿了。实现以下功能:

发表留言(增) 查看留言(查)

管理员回复留言(改) 管理员删除留言(删除)

首先,创建一个Default.aspx,在页面上加入一些控件:

? ? ? ?

> 姓名

留言

<%# Eval(\

<%# Eval(\

管理员回复:<%# Eval(\暂无\


div>

你可能很难想象,使用Linq to sql进行数据访问会是这么简单,后台代码: c partial class _Default : System.Web.UI.Page

estBookDataContext ctx = new GuestBookDataContext(\

otected void Page_Load(object sender, EventArgs e)

f (!IsPostBack) {

SetBind(); }

otected void btn_SendMessage_Click(object sender, EventArgs e)

bGuestBook gb = new tbGuestBook(); D = Guid.NewGuid();

gb.UserName = tb_UserName.Text; gb.Message = tb_Message.Text; gb.IsReplied = false;

gb.PostTime = DateTime.Now; ctx.tbGuestBooks.Add(gb); ctx.SubmitChanges(); SetBind();

vate void SetBind()

rpt_Message.DataSource = from gb in ctx.tbGuestBooks orderby gb.PostTime descending select gb; rpt_Message.DataBind();

前面创建Linq to sql Classes的时候我们输入名字GuestBook,系统就为我们自动创建了GuestBookDataContext(你也可以在GuestBook.Designer.cs中找到类定义)。在绑定的时候我们使用查询句法查询留言表中所有留言,按照发表时间倒序(天哪?这是数据访问吗?好像仅仅定义了一句SQL啊)。在发表留言按钮中,我们为一个tbGuestBook赋值,然后把它加入留言表,再提交更改,就这样完成了记录的插入。 运行效果如下图:

然后,再创建一个Admin.aspx,前台代码如下:

<%# Eval(\


后台代码:

public partial class Admin : System.Web.UI.Page {

GuestBookDataContext ctx = new GuestBookDataContext(\

protected void Page_Load(object sender, EventArgs e) {

if (!IsPostBack) {

SetBind(); } }

private void SetBind() {

rpt_Message.DataSource = from gb in ctx.tbGuestBooks orderby gb.PostTime descending select gb; rpt_Message.DataBind(); }

protected void rpt_Message_ItemCommand(object source, RepeaterCommandEventArgs e) {

if (e.CommandName == \ {

StreamWriter sw = new StreamWriter(Server.MapPath(\ ctx.Log = sw;

tbGuestBook gb = ctx.tbGuestBooks.Single(b => b.ID == new Guid(e.CommandArgument.ToString())); ctx.tbGuestBooks.Remove(gb); ctx.SubmitChanges(); SetBind(); sw.Close(); }

if (e.CommandName == \ {

StreamWriter sw = new StreamWriter(Server.MapPath(\ ctx.Log = sw;

tbGuestBook gb = ctx.tbGuestBooks.Single(b => b.ID == new Guid(e.CommandArgument.ToString())); gb.Reply = ((TextBox)e.Item.FindControl(\ gb.IsReplied = true; ctx.SubmitChanges(); SetBind(); sw.Close(); } } }

运行效果如下图:

在这里,我们通过Single方法获取一条记录,也就是一个tbGuestBook实例,更新了一些属性后保存也就完成了改这个操作。删除操作更简单,只需要从表中移除对象。你是不是觉得好像不是在操作数据库,像在操作内存中的对象。 由于写了日志,看看改和删操作会是怎么样的SQL?

@p5

Name] = @p1) AND ([PostTime] = @p2) AND ([Message] = @p3) AND (NOT ([IsReplied] = 1)) AND ([Reply] IS NULL) 0; Scale = 0) [00000000-0000-0000-0000-000000000000] = 0; Scale = 0) [ghgh]

rec = 0; Scale = 0) [2007-8-16 10:20:09] = 0; Scale = 0) [ghj] c = 0; Scale = 0) [True] = 0; Scale = 0) [qqq]

odel: AttributedMetaModel Build: 3.5.20706.1

k] WHERE ([ID] = @p0) AND ([UserName] = @p1) AND ([PostTime] = @p2) AND ([Message] = @p3) AND (NOT ([IsR 0; Scale = 0) [158ec941-13ff-4093-bd8b-9fceae152171] = 0; Scale = 0) [44]

rec = 0; Scale = 0) [2007-8-16 9:56:19] = 0; Scale = 0) [44] = 0; Scale = 0) [222]

odel: AttributedMetaModel Build: 3.5.20706.1

今天就讲到这里,下次将系统介绍查询句法。

一步一步学Linq to sql(四):查询句法

2007-10-18 09:00 作者: lovecherry 出处: 天极网 责任编辑:>dizzarz select

描述:查询顾客的公司名、地址信息 查询句法:

var 构建匿名类型1 = from c in ctx.Customers

select new {

公司名 = c.CompanyName, 地址 = c.Address };

对应SQL:

SELECT [t0].[CompanyName], [t0].[Address] FROM [dbo].[Customers] AS [t0] 描述:查询职员的姓名和雇用年份 查询句法:

var 构建匿名类型2 = from emp in ctx.Employees select new {

姓名 = emp.LastName + emp.FirstName, 雇用年 = emp.HireDate.Value.Year }; 对应SQL:

SELECT [t0].[LastName] + [t0].[FirstName] AS [value], DATEPART(Year, [t0].[HireDate]) AS [value2] FROM [dbo].[Employees] AS [t0]

描述:查询顾客的ID以及联系信息(职位和联系人) 查询句法:

var 构建匿名类型3 = from c in ctx.Customers

select new {

ID = c.CustomerID, 联系信息 = new

{

职位 = c.ContactTitle, 联系人 = c.ContactName } };

对应SQL:

SELECT [t0].[CustomerID], [t0].[ContactTitle], [t0].[ContactName] FROM [dbo].[Customers] AS [t0] 描述:查询订单号和订单是否超重的信息 查询句法:

var select带条件 = from o in ctx.Orders select new {

订单号 = o.OrderID,

是否超重 = o.Freight > 100 ? \是\否\ };

对应SQL:

SELECT [t0].[OrderID], (CASE

WHEN [t0].[Freight] > @p0 THEN @p1 ELSE @p2

END) AS [value]

FROM [dbo].[Orders] AS [t0]

-- @p0: Input Currency (Size = 0; Prec = 19; Scale = 4) [100] -- @p1: Input String (Size = 1; Prec = 0; Scale = 0) [是] -- @p2: Input String (Size = 1; Prec = 0; Scale = 0) [否]

where

描述:查询顾客的国家、城市和订单数信息(可以使用sql语句来表示),要求国家是法国并且订单数大于5 查询句法:

// var result = (from m in methods // where m.IsStatic != true // select m.Name).Distinct();

var 多条件 = from c in ctx.Customers

where c.Country == \ select new {

国家 = c.Country, 城市 = c.City,

订单数 = c.Orders.Count }; 对应SQL:

SELECT [t0].[Country], [t0].[City], ( SELECT COUNT(*)

FROM [dbo].[Orders] AS [t2]

WHERE [t2].[CustomerID] = [t0].[CustomerID] ) AS [value]

FROM [dbo].[Customers] AS [t0]

WHERE ([t0].[Country] = @p0) AND ((( SELECT COUNT(*)

FROM [dbo].[Orders] AS [t1]

WHERE [t1].[CustomerID] = [t0].[CustomerID] )) > @p1)

-- @p0: Input String (Size = 6; Prec = 0; Scale = 0) [France] -- @p1: Input Int32 (Size = 0; Prec = 0; Scale = 0) [5]

orderby

描述:查询所有没有下属雇员的雇用年和名,按照雇用年倒序,按照名正序 查询句法:

var 排序 = from emp in ctx.Employees where emp.Employees.Count == 0

orderby emp.HireDate.Value.Year descending, emp.FirstName ascending select new {

雇用年 = emp.HireDate.Value.Year, 名 = emp.FirstName };

对应SQL:

SELECT DATEPART(Year, [t0].[HireDate]) AS [value], [t0].[FirstName] FROM [dbo].[Employees] AS [t0] WHERE ((

SELECT COUNT(*)

FROM [dbo].[Employees] AS [t1]

WHERE [t1].[ReportsTo] = [t0].[EmployeeID] )) = @p0

ORDER BY DATEPART(Year, [t0].[HireDate]) DESC, [t0].[FirstName] -- @p0: Input Int32 (Size = 0; Prec = 0; Scale = 0) [0]

分页

描述:按照每页10条记录,查询第二页的顾客 查询句法:

var 分页 = (from c in ctx.Customers select c).Skip(10).Take(10); 对应SQL:

], [t1].[Address], [t1].[City], [t1].[Region], [t1].[PostalCode], [t1].[Country], [t1].[Phone], [t1].[Fax]

ntactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0], [t0].[Fax]

分组

描述:根据顾客的国家分组,查询顾客数大于5的国家名和顾客数 查询句法:

Select count(guke) from Customers grop by Country var 一般分组 = from c in ctx.Customers group c by c.Country into g where g.Count() > 5

orderby g.Count() descending select new {

国家 = g.Key,

顾客数 = g.Count() }; 对应SQL:

SELECT [t1].[Country], [t1].[value3] AS [顾客数] FROM (

SELECT COUNT(*) AS [value], COUNT(*) AS [value2], COUNT(*) AS [value3], [t0].[Country] FROM [dbo].[Customers] AS [t0] GROUP BY [t0].[Country] ) AS [t1]

WHERE [t1].[value] > @p0

ORDER BY [t1].[value2] DESC

-- @p0: Input Int32 (Size = 0; Prec = 0; Scale = 0) [5]

描述:根据国家和城市分组,查询顾客覆盖的国家和城市 查询句法:

var 匿名类型分组 = from c in ctx.Customers group c by new { c.City, c.Country } into g orderby g.Key.Country, g.Key.City select new {

国家 = g.Key.Country, 城市 = g.Key.City };

对应SQL:

SELECT [t1].[Country], [t1].[City] FROM (

SELECT [t0].[City], [t0].[Country] FROM [dbo].[Customers] AS [t0] GROUP BY [t0].[City], [t0].[Country] ) AS [t1]

ORDER BY [t1].[Country], [t1].[City]

描述:按照是否超重条件分组,分别查询订单数量 查询句法:

var 按照条件分组 = from o in ctx.Orders

group o by new { 条件 = o.Freight > 100 } into g select new {

数量 = g.Count(),

是否超重 = g.Key.条件 ? \是\否\ }; 对应SQL:

SELECT (CASE

WHEN [t2].[value2] = 1 THEN @p1 ELSE @p2

END) AS [value], [t2].[value] AS [数量] FROM (

SELECT COUNT(*) AS [value], [t1].[value] AS [value2] FROM ( SELECT (CASE

WHEN [t0].[Freight] > @p0 THEN 1

WHEN NOT ([t0].[Freight] > @p0) THEN 0 ELSE NULL END) AS [value]

FROM [dbo].[Orders] AS [t0] ) AS [t1]

GROUP BY [t1].[value] ) AS [t2]

-- @p0: Input Currency (Size = 0; Prec = 19; Scale = 4) [100] -- @p1: Input String (Size = 1; Prec = 0; Scale = 0) [是] -- @p2: Input String (Size = 1; Prec = 0; Scale = 0) [否]

distinct

描述:查询顾客覆盖的国家 查询句法:

var 过滤相同项 = (from c in ctx.Customers orderby c.Country select c.Country).Distinct();

对应SQL:

SELECT DISTINCT [t0].[Country] FROM [dbo].[Customers] AS [t0] union

描述:查询城市是A打头和城市包含A的顾客并按照顾客名字排序 查询句法:

var 连接并且过滤相同项 = (from c in ctx.Customers where c.City.Contains(\

(from c in ctx.Customers where c.ContactName.StartsWith(\

对应SQL:

.[CompanyName], [t3].[ContactName], [t3].[ContactTitle], [t3].[Address], [t3].[City], [t3].[Region], [t3].[PostalCode], [t3].[

.[CompanyName], [t2].[ContactName], [t2].[ContactTitle], [t2].[Address], [t2].[City], [t2].[Region], [t2].[PostalCode], [t2].[

.[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[AS [t0] @p0

.[CompanyName], [t1].[ContactName], [t1].[ContactTitle], [t1].[Address], [t1].[City], [t1].[Region], [t1].[PostalCode], [t1].[AS [t1]

] LIKE @p1

ame]

3; Prec = 0; Scale = 0) [%A%]

2; Prec = 0; Scale = 0) [A%]

concat

描述:查询城市是A打头和城市包含A的顾客并按照顾客名字排序,相同的顾客信息不会过滤 查询句法:

var 连接并且不过滤相同项 = (from c in ctx.Customers where c.City.Contains(\

(from c in ctx.Customers where c.ContactName.StartsWith(\

对应SQL:

SELECT [t3].[CustomerID], [t3].[CompanyName], [t3].[ContactName], [t3].[ContactTitle], [t3].[Address], [t3].[City], [t3].[Region], [t3].[PostalCode], [t3].[Country], [t3].[Phone], [t3].[Fax] FROM (

SELECT [t2].[CustomerID], [t2].[CompanyName], [t2].[ContactName], [t2].[ContactTitle], [t2].[Address], [t2].[City], [t2].[Region], [t2].[PostalCode], [t2].[Country], [t2].[Phone], [t2].[Fax] FROM (

SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax] FROM [dbo].[Customers] AS [t0] WHERE [t0].[City] LIKE @p0 UNION ALL

SELECT [t1].[CustomerID], [t1].[CompanyName], [t1].[ContactName], [t1].[ContactTitle], [t1].[Address], [t1].[City], [t1].[Region], [t1].[PostalCode], [t1].[Country], [t1].[Phone], [t1].[Fax] FROM [dbo].[Customers] AS [t1]

WHERE [t1].[ContactName] LIKE @p1 ) AS [t2] ) AS [t3]

ORDER BY [t3].[ContactName]

-- @p0: Input String (Size = 3; Prec = 0; Scale = 0) [%A%] -- @p1: Input String (Size = 2; Prec = 0; Scale = 0) [A%] 取相交项

描述:查询城市是A打头的顾客和城市包含A的顾客的交集,并按照顾客名字排序 查询句法:

var 取相交项 = (from c in ctx.Customers where c.City.Contains(\

(from c in ctx.Customers where c.ContactName.StartsWith(\

对应SQL:

CompanyName], [t1].[ContactName], [t1].[ContactTitle], [t1].[Address], [t1].[City], [t1].[Region], [t1].[PostalCode], [t1].[C

], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode],

].[CustomerID]) AND ([t2].[ContactName] LIKE @p0)

ec = 0; Scale = 0) [A%] ec = 0; Scale = 0) [%A%]

排除相交项

描述:查询城市包含A的顾客并从中删除城市以A开头的顾客,并按照顾客名字排序 查询句法:

var 排除相交项 = (from c in ctx.Customers where c.City.Contains(\

(from c in ctx.Customers where c.ContactName.StartsWith(\

对应SQL:

SELECT [t1].[CustomerID], [t1].[CompanyName], [t1].[ContactName], [t1].[ContactTitle], [t1].[Address], [t1].[City], [t1].[Region], [t1].[PostalCode], [t1].[Country], [t1].[Phone], [t1].[Fax] FROM (

SELECT DISTINCT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax] FROM [dbo].[Customers] AS [t0] ) AS [t1]

WHERE (NOT (EXISTS( SELECT NULL AS [EMPTY] FROM [dbo].[Customers] AS [t2]

WHERE ([t1].[CustomerID] = [t2].[CustomerID]) AND ([t2].[ContactName] LIKE @p0)

))) AND ([t1].[City] LIKE @p1) ORDER BY [t1].[ContactName]

-- @p0: Input String (Size = 2; Prec = 0; Scale = 0) [A%]

-- @p1: Input String (Size = 3; Prec = 0; Scale = 0) [%A%] 子查询

描述:查询订单数超过5的顾客信息 查询句法:

var 子查询 = from c in ctx.Customers where

(from o in ctx.Orders group o by o.CustomerID into o where o.Count() > 5 select o.Key).Contains(c.CustomerID) select c;

对应SQL:

SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax]

FROM [dbo].[Customers] AS [t0] WHERE EXISTS(

SELECT NULL AS [EMPTY] FROM (

SELECT COUNT(*) AS [value], [t1].[CustomerID] FROM [dbo].[Orders] AS [t1] GROUP BY [t1].[CustomerID] ) AS [t2]

WHERE ([t2].[CustomerID] = [t0].[CustomerID]) AND ([t2].[value] > @p0) )

-- @p0: Input Int32 (Size = 0; Prec = 0; Scale = 0) [5] in操作

描述:查询指定城市中的客户 查询句法:

var in操作 = from c in ctx.Customers

where new string[] { \ select c; 对应SQL:

SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax] FROM [dbo].[Customers] AS [t0]

WHERE [t0].[City] IN (@p0, @p1, @p2)

-- @p0: Input String (Size = 11; Prec = 0; Scale = 0) [Brandenburg] -- @p1: Input String (Size = 5; Prec = 0; Scale = 0) [Cowes] -- @p2: Input String (Size = 7; Prec = 0; Scale = 0) [Stavern] join

描述:内连接,没有分类的产品查询不到 查询句法:

var innerjoin = from p in ctx.Products join c in ctx.Categories

on p.CategoryID equals c.CategoryID select p.ProductName; 对应SQL:

SELECT COUNT(*) AS [value] FROM [dbo].[Products] AS [t0]

INNER JOIN [dbo].[Categories] AS [t1] ON [t0].[CategoryID] = ([t1].[CategoryID]) 描述:外连接,没有分类的产品也能查询到 查询句法:

var leftjoin = from p in ctx.Products join c in ctx.Categories

on p.CategoryID equals c.CategoryID into pro

from x in pro.DefaultIfEmpty() select p.ProductName; 对应SQL:

SELECT COUNT(*) AS [value] FROM [dbo].[Products] AS [t0]

LEFT OUTER JOIN [dbo].[Categories] AS [t1] ON [t0].[CategoryID] = ([t1].[CategoryID]) 你可能会很奇怪,原先很复杂的SQL使用查询句法会很简单(比如按照条件分组)。但是原先觉得很好理解的SQL使用查询句法会觉得很复杂(比如连接查询)。其实,我们还可以通过其它方式进行连接操作,在以后说DataLoadOptions类型的时候会再说。虽然Linq to sql已经非常智能了,但是对于非常复杂的查询还是建议通过存储过程实现,下次讲解如何调用存储过程。

一步一步学Linq to sql(五):存储过程

2007-10-20 00:00 作者: LoveCherry 出处: 天极网 责任编辑:>dizzarz 普通存储过程

首先在查询分析器运行下面的代码来创建一个存储过程:

create proc sp_singleresultset as

set nocount on

select * from customers

然后打开IDE的服务器资源管理器,之前我们从表中拖动表到dbml设计视图,这次我们从存储过程中找到刚才创建的存储过程,然后拖动到设计视图。在方法面板中可以看到已经创建了一个sp_singleresultset的方法,如下图:

然后打开Northwind.designer.cs,可以找到下面的代码:

[Function(Name=\ public ISingleResult sp_singleresultset() {

IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod()))); return ((ISingleResult)(result.ReturnValue));

}

我们可以发现,IDE为这个存储过程单独生成了返回结果集的实体定义,你可能会觉得很奇怪,IDE怎么知道这个存储过程将会返回哪些数据那?其实,在把存储过程拖拽入dbml设计视图的时候,IDE就执行了类似下面的命令:

SET FMTONLY ON;

exec Northwind.dbo.sp_singleresultset SET FMTONLY OFF;

这样就可以直接获取存储过程返回的元数据而无须执行存储过程。 其实我们存储过程返回的就是顾客表的数据,如果你觉得为存储过程单独设置结果集实体有些浪费的话可以在存储过程的属性窗口中调整返回类型从“自动生成的类型”到Customer,不过以后你只能通过删除方法面板中的存储过程,然后重新添加来还原到“自动生成的类型”。下面,我们可以写如下的Linq to object代码进行查询:

var 单结果集存储过程 =

from c in ctx.sp_singleresultset()

where c.CustomerID.StartsWith(\ select c;

在这里确实是Linq to object的,因为查询句法不会被整句翻译成SQL,而是从存储过程的返回对象中再去对对象进行查询。SQL代码如下:

EXEC @RETURN_VALUE = [dbo].[sp_singleresultset]

-- @RETURN_VALUE: Output Int32 (Size = 0; Prec = 0; Scale = 0) [] 带参数的存储过程 创建如下存储过程:

create proc [dbo].[sp_withparameter] @customerid nchar(5), @rowcount int output as

set nocount on

set @rowcount = (select count(*) from customers where customerid = @customerid)

使用同样的方法生成存储过程方法,然后使用下面的代码进行测试:

int? rowcount = -1;

ctx.sp_withparameter(\ Response.Write(rowcount);

ctx.sp_withparameter(\ Response.Write(rowcount);

结果输出了“01”。说明ID为“”的顾客数为0,而ID为“ALFKI”的顾客数为1。存储过程的输出参数被封装成了ref参数,对于C#语法来说非常合情合理。SQL代码如下:

EXEC @RETURN_VALUE = [dbo].[sp_withparameter] @customerid = @p0, @rowcount = @p1 OUTPUT -- @p0: Input StringFixedLength (Size = 5; Prec = 0; Scale = 0) [] -- @p1: InputOutput Int32 (Size = 0; Prec = 0; Scale = 0) [-1]

-- @RETURN_VALUE: Output Int32 (Size = 0; Prec = 0; Scale = 0) []

带返回值的存储过程 再来创建第三个存储过程:

create proc [dbo].[sp_withreturnvalue]

@customerid nchar(5) as

set nocount on

if exists (select 1 from customers where customerid = @customerid) return 101 else

return 100

生成方法后,可以通过下面的代码进行测试:

Response.Write(ctx.sp_withreturnvalue(\

Response.Write(ctx.sp_withreturnvalue(\ 运行后程序输出“100101” 多结果集的存储过程

再来创建一个多结果集的存储过程:

create proc [dbo].[sp_multiresultset] as

set nocount on

select * from customers select * from employees

找到生成的存储过程方法:

[Function(Name=\ public ISingleResult sp_multiresultset() {

IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod()))); return ((ISingleResult)(result.ReturnValue)); }

由于现在的VS2008会把多结果集存储过程识别为单结果集存储过程(只认识第一个结果集),我们只能对存储过程方法多小动手术,修改为:

[Function(Name=\ [ResultType(typeof(Customer))] [ResultType(typeof(Employee))]

public IMultipleResults sp_multiresultset() {

IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod()))); return (IMultipleResults)(result.ReturnValue); }

然后使用下面的代码测试:

var 多结果集存储过程 = ctx.sp_multiresultset();

var Customers = 多结果集存储过程.GetResult(); var Employees = 多结果集存储过程.GetResult(); GridView1.DataSource = from emp emp.FirstName.Contains(\ GridView1.DataBind();

GridView2.DataSource = from c.CustomerID.StartsWith(\ GridView2.DataBind();

使用存储过程新增数据

存储过程除了可以直接调用之外,还可以用于实体的增删改操作。还记得在《一步一步学Linq to sql(三):增删改》中创建的留言簿程序吗?下面我们就来改

c

in

Customers

where

in

Employees

where

本文来源:https://www.bwwdw.com/article/9wq6.html

Top