linq表达式
Linq简介
OO(面向对象)以外的疆域:信息的访问与整合。关系数据库与XML为其中的典型应用。
.NET Language Integrated Query (LINQ):不采
用特定于关系数据库或者XML的专有方案,而采用
通用方案来解决各种信息源的访问与整合问题。
在LINQ中,查询成为编程语言的一个组成部分,这使得查询表达式可以得到很好的编译时语法检查,丰富的元数据,智能感知等强类型语言的好处
下面先看下linq表达式代码吧:
class app {
static void Main() {
string[] names = { "Burke", "Connor", "Frank",
"Everett", "Albert", "George",
"Harris", "David" };
IEnumerable<string> query = from s in names
where s.Length == 5
orderby s
select s.ToUpper();
foreach (string item in query)
Console.WriteLine(item);
}
}
查询表达式解析(1)
IEnumerable<string> query = from s in names
where s.Length == 5
orderby s
select s.ToUpper();
在语义上等同于如下“方法风格(基于方法)的查询”:
IEnumerable<string> query = names
.Where(s => s.Length == 5)
.OrderBy(s => s)
.Select(s => s.ToUpper());
查询表达式解析(2)
注意其中的参数为lambda 表达式,类似于如下委托:
Func<string, bool> filter = delegate (string s) {
return s.Length == 5;};
Func<string, string> extract = delegate (string s) {
return s; };
Func<string, string> project = delegate (string s) {
return s.ToUpper(); };
IEnumerable<string> query = names.Where(filter)
.OrderBy(extract)
.Select(project);
查询操作符与扩展方法解析(1)
查询操作符是LINQ中的另外一项重要设施,LINQ使
用扩展方法来定义查询操作符,例如where操作符:
namespace System.Linq {
public static class Enumerable {
public static IEnumerable<T> Where<T>(
this IEnumerable<T> source, Func<T, bool> predicate) {
foreach (T item in source)
if (predicate(item))
yield return item;
}
}
}
查询操作符与扩展方法解析(2)
普通的方式来调用扩展方法:
IEnumerable<string> query = Enumerable.Where(names,
s => s.Length < 6);
C#语言允许我们使用如下的方式来调用扩展方法:
IEnumerable<string> query = names.Where(s => s.Length < 6);
LINQ to SQL简介
面向对象领域:一切围绕对象(字段,方法,引用…)
关系型数据库领域:一切围绕表格数据(行,列,关系)
Linq to SQL 将SQL的模式信息集成到CLR元数据中,自然地将面向对象领域的对象与关系型数据库中的表格数据相互转化,从而允许我们使用LINQ来便捷地访问关系数据库,
Linq to SQL是作为ADO.NET的一个重要组件,而
非完全替代品。
实体类映射
[Table(Name = "Category")]
public class Category
{
[Column(IsPrimaryKey = true)]
public string CategoryId;
[Column]
public string Name;
[Column]
public string Descn;
}
注意,其中的[Table] 特性表示将Category类与数据库中名
称为Category的表相对应。[Column] 特性则对应数据库中的
列。
DataContext 数据上下文对象
DataContext db = new DataContext("Password=sasa;UserID=sa;Initial Catalog=Pubs;DataSource=.");
Table<Category> Categorys = db.GetTable<Category>();
var result =
from c in Categorys
select c;
注意,DataContext非常类似于数据库链接对象,但是它为Linq to SQL提供了更多支持。
定义基本关系(1)
[Table(Name = "jobs")]
public class Jobs
{
private EntitySet<Employee> employee;//对于jobs表employee是多的一方所以是实体集合
[Association(Storage = "employee", OtherKey = "emp_id")]//
public EntitySet<Employee> Employee
{
get
{
return this.employee;
}
set
{
this.employee.Assign(value);
}
}
}
注意, employee 映射了jobs与employee之间的一对多关系。
定义基本关系(2)
[Table(Name = "employee")]
public class Employee
{
private EntityRef<Jobs> job;//对于employee表jobs是一所以是引用
[Association(Storage = "job", ThisKey = "job_id")]
public Jobs Job
{
get
{
return this.job.Entity;
}
set
{
this.job.Entity = value;
}
}
}
注意, job 映射了employee与jobs之间的多对一关系。
Linq查询执行过程
Table<Product> Products = db.GetTable<Product>();
var result =from c in Products
where c.Price>500
select c;
foreach(Product p in result){
…….
}
注意,result变量仅仅是对Linq查询的一个描述,而非执行结果。换言之,Linq查询语句并不立即执行得到结果,而是将查询缓存在变量result中,如果是一个错误的查询如实体类字段不能正确影射数据库中的表列,错误不会发生在result=这一行而是发生下面的foreach语句块。
那么result 的类型是什么呢?IQueryable<Product>
IQueryable<T>类型
namespace System.Linq
{
public interface IQueryable : IEnumerable
{
Type ElementType { get; }
Expression Expression { get; }
IQueryable CreateQuery(Expression expression);
object Execute(Expression expression);
}
public interface IQueryable<T> : IEnumerable<T>,
IQueryable, IEnumerable
{
IQueryable<TElement> CreateQuery<TElement>(Expression exp);
TResult Execute<TResult>(Expression exp);
}
}
Linq执行与IQueryable<T> 接口
var result =from c in Products
where c.Price>500
select c;
foreach(Product p in result){
…….
}
IQueryable<T> 只是查询表示,类似于SqlCommand等命令表示,真正的查询执行要依赖于在其上的调用操作。只不过SqlCommand表达查询的是一个查询字符串,而IQueryable<T> 表达查询的是一个Expression强类型数据结构。大家想一想如果你不做这样的代码:cmd.ExecuteReader();是不会在数据库层面上执行操作的.
foreach语句会导致IQueryable<T> 上的方法GetEnumerator()执行,从而导致查询的执行,并将返回结果IEnumerator<T>,就是说GetEnumerator()方法将导致在数据库上执行操作,如果有任何不匹配错误将在这里发生
Linq延迟执行
var result =from c in Products
where c.Price>500
select c;
foreach(Product p in result){
Console.WriteLine(p.Name);
}
foreach(Product p in result){
Console.WriteLine(p.Name);
}
因此,对于上述程序,两个foreach语句块会导致查询被执行两次, 这种行为被称作Linq延迟执行。如果使用不当,会导致各种程序效率问题,比如大量的数据绑定如果都做得是Linq延迟执行,程序效率将会大大降低。
改进Linq延迟执行
var result =from c in Products
where c.Price>500
select c;
var list=result.ToList<Product>
foreach(Product p in list){
Console.WriteLine(p.Name);
}
foreach(Product p in list){
Console.WriteLine(p.Name);
}
通过调用ToList或者ToArray方法,可以直接执行Linq查询,将查询结果缓存在list变量中。从而可以避免Linq延迟执行的效率问题。