[转载]使用linq的ToArray() ToList() ToDictionary()

[转载]Linq 中的琐碎东西 – 天涯走狗 – 博客园.

使用linq的ToArray() ToList() ToDictionary()

当我们对某个Ienumerable<T>对象下达where等条件式时,所取得的结果会是一个实现了 Ienumerable<T>接口的对象,此时所有指定的条件式都尚未执行比对的操作,而只是的到了一个WhereIterator对象,拿 到了由编译器对linq expression 进行分析之后所建立的delegate 和string。当通过此Ienumerable<T>对象获得Enumerator对象,并调用MoveNext函数时(foreach会 触发该函数),where Iterator开始起作用,该对象才会一笔一笔地对元素进行条件比对。这一模式不仅用于LINQ TO Objects, 同时也用于LINQ To XML, LINQ ToDataSet 乃至LINQ To SQL, LINQ TO Entities。

但ToArray()等函数会以foreach一一巡览Ieunmerable<T>对象中的所有元素并进行比较,然后将符合条件的元素方放在Array中返回。

那么,操作这样一个比较过的Array 或者 List 对象,显然比直接操作必须在取得元素前进行比对条件的对象集来的有效率

LINQ Expression无法完全取代函数调用。以Where为例。当使用函数时,我们可以写下很复杂的Lambda Exression

Var pq = new[]{"ybwang", "dingmeng", "yhzhou"}
Var p5 = p1.Where(
	x=>{
		Bool result = false;
		sqlConnection conn = new SqlConnection("…...");
		Conn.Open();
		Return result;
	}
)

这是无法以单纯的LINQ Expression 办到的,如果硬要以LINQ Expression 来完成,就必须使用静态函数或者是Extension Method 才行。所以学会如何调用Extension Method 以及运用 Lambda Expression, 是活用Linq to Object 的不二法门。

C#3.0只是单纯地把LINQ Expression 转成object.Select(),

如果你自己打造了一个类Persons<T>,

Public class Persons<T>{
	Private List<T> _list = new List<t>();
	Public T this[int index]
	{
		Get{
			Return _list[index];
		}
	}

	Public void add[T item]{
		_list.Add(item);
	}
}

你用from o in Persons1 select o 的时候,由于这个类没有实现Ienumerable<T>接口,则它将该Lambda表达式转换为Select()方法之后,会因为找不到这 个方法而报错。于是你得自己写个Extension方法,示例如下

public static class PersonsExtension{
	public static Persons<TResult> Select<TSource, TResult>(this Persons<TSource>, Func<TSource, TResult> selector){
		//select elements using the Fucn
		//return result;        
	}
}

可见,选择过程的控制权在我们手上

Linq to SQL 查询返回的那个东西,代表这一组SQL语句,也就是说你写下var result = from …..的时候并没有去数据库进行查询,当你真正用到数据时,比如对result进行foreach时,才会用result里头的sql语句去数据库进行查 询,查询过程 默认使用的是连接模式,即用sqlDataReader来读数据。

示例一

aDataContext c = new aDataContext();

var result1 = from c1 in c.Customers select c1;
var result2 = from c2 in c.Customers select c2;

foreach(var item in result1){
	foreach(var item2 in result2){
		//do something
	}
}

这是可以的,由于result1和result2属于同一个context,当result2开始去尝试连接数据库时,result1会把它要的数据全部提取出来,缓存到一个DataTable中,然后绑定到该DataTable,好让result2绑定到数据库

实例二

aDataContext c1 = new aDataContext();
aDataContext c2 = new aDataContext();

var result1 = from c1 in c1.Customers select c1;
var result2 = from c2 in c2.Customers select c2;

foreach(var item in result1){
	foreach(var item2 in result2){
		//do something
	}
}

就不行了,因为这种缓存机制之适应于同一个dataContext的不同result

有些适用于Linq to Object 的语法,并不适用于Linq to SQL

示例

static void main(string [] args){
	var list = new [] {"A", "B", "C"};
	var result = from s1 in list where CheckMe(s1) select s1;
	
	foreach(var item in result){}
}	

static bool CheckMe(string item){
	return true;
}


这是可以的,但在Linq to SQL中

static void main(string [] args){
	aDataContext context = new aDataContext();	
	var result = from s1 in context.Customers where CheckMe(s1) select s1;

	foreach(var item in result){}	
}

static bool CheckMe(string item){
	return true;
}

这是不行的,因为linq不知道该如何将CheckMe函数转化成sql语句。

这种情况,你可已先调用ToArray或者ToList函数,使得取回的对象变为一般的Collection,于是就进入了Linq to Object 的范围,可以用Linq to Object 来操作它了。

在LINQ TO SQL 默认模式中,调用submitChanges函数更新数据之前会激活一个Transaction,若期间发生任何错误时会抛出一个异常,终止更新操作并调用Transcation的RollBack函数来恢复事务前的状态。

Linq to sql 为Entity Class的每个属性提供了Delay Load 属性,当该属性的Delay Load被设置为True时,Linq to SQL于撷取时便不会撷取该字段,而是等到该属性第一次被访问时才下达一个SQL指令由数据库撷取该字段数据。往往将一些二进制data的 Delay Load设置成true

在lts(Linq To SQL)中使用select new 时,所select 出来的对象是只读的。这些对象和数据库里边的行并没有什么联系,不像是直接选出来的那些Entity Object, 你修改他们再调用context.Submit(),就会将修改提交到数据库

class Program{
	static void Main(string[] args){
		test();
	}

	static test(){
		aDataContext context = new aDataConetxt();
		var result = context.ExecuteQuery<OrdersWithTotal>("select orderId, sum(UnitPrice * Quantity) as Totla from [Order Details] group by orderId");

		foreach(var item in result){
			Console.WriteLine("Order Id: {0} Total : {1}", item.OrderId, item.Total);
		}
	}
}

public class OrdersWithTotal{
	public int OrderId{get; set}
	public Decimal Total{get; set}
}

当 Linq to Sql 无法满足要求时,可以用ExecuteQuery函数来直接执行SQL指令。它需要一个类型参数,该函数为每一行创建指定类型的对象,此处就是 OrderWithTotal.然后将相同名字的字段值填入同名的属性。这也是为何查询语句里会出现as Total 的缘故。as Total ,则生成的OrdersWithTotal对象的Total属性会是空的。

DataContext有一个Translate<T>(IDataReader)函数,用于从实现了IDataReader的对象中获取实体对象

相比于ExecuteQuery(), Translate()是架构与IDataReader之上,所以我们可以通过ODBC、OLEDB、Oracle等ADO.Net Provider将取得的IDataReader对象转成Entity Objects,对于转文件、汇入等功能来说,Translate函数相当好用。

但它有个限制,就是只能对返回对象做一次foreach,不过我们仍然可以通过ToList来跨越此限制

另外,该函数执行之后,所取得的Entity Object 会被加入到DataContext中,受dataContext所管辖,因此你可以对这些对象做修改,然后调用dataContext.Submit将改后的数据写回数据库

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏