如何使用LINQ TO SQL 技术
1、LINQ to Object使用的命名空间是:System.Linq,而LINQ to SQL使用的命名空间是System.Data.Linq。
这是一个简单的LINQ to Object的例子:
2、static IEnumerable<int> FindGreaterThan5(IEnumerable<int> list)
{
foreach (var i in list)
{
if (i >= 5)
yield return i;
}
}
static void Main(string[] args)
{
List<int> listTest = new List<int>{ 8, 2, 7, 9, 1, 5, 3, 4 };
//找出所有大于等于5的数
IEnumerable<int> result = FindGreaterThan5(listTest);
foreach (var i in result)
{
Console.WriteLine(i);
}
}
3、其中FindGreaterThan5的代码可以用LINQ to Object改为:
static IEnumerable<int> FindGreaterThan5(IEnumerable<int> list) { return list.Where(i => i >= 5); }
4、像上述例子的那种使用yield return的方式返回一个可枚举类型的函数,都会被“延迟”执行,要证明这点很简单,改一下上面的代码:
5、static IEnumerable<int> FindGreaterThan5(IEnumerable<int> list)
{
foreach (var i in list)
{
if (i >= 5)
yield return i;
else
{
throw new Exception("你看不到这个异常");
}
}
}
static void Main(string[] args)
{
List<int> listTest = new List<int>{ 8, 2, 7, 9, 1, 5, 3, 4 };
//找出所有大于等于5的数
IEnumerable<int> result = FindGreaterThan5(listTest);
}
6、这个程序执行没有任何问题,你看不到异常,因为FindGreaterThan5根本没有被执行,它只有在返回结果被用到的时候才会真正去执行(这样做的好处后面会提到)。如果你把foreach加上,改为:
7、static void Main(string[] args)
{
List<int> listTest = new List<int>{ 8, 2, 7, 9, 1, 5, 3, 4 };
//找出所有大于等于5的数
IEnumerable<int> result = FindGreaterThan5(listTest);
foreach (var i in result)
{
Console.WriteLine(i);
}
}
8、那这个异常就会出现,这个地方是要十分小心的,假如你这么写:
IEnumerable<int> result; try { result = FindGreaterThan5(listTest); } catch(Exception) //你捕捉不到异常的 { return; }
9、那是捕捉不到异常的,因为它实际上发生的地方是接下来的foreach处。解决方法有两种,一是try foreach语句,另一是“再包一层”,创建一个“Roll”函数:
static IEnumerable<int> FindGreaterThan5Roll(IEnumerable<int> list) { return FindGreaterThan5(list); }
然后try这个函数。
10、跟LINQ to Object一样,LINQ to SQL能够使得你对Microsoft SQL Server的访问代码变得简洁,它是对ADO.net的封装。所以它并非ADO.net的替代品,也不能带来执行效率上的提高(用的不好反而会更低效)。这里还需要特别说明的是:
只能用于Microsoft SQL Server这套DBMS,2005版及2008版我都试过,没问题。Oracle?MySQL?没门;
使用LINQ to SQL其实仍然是使用ADO.net,只是LINQ to SQL帮助你生成各个查询语句,不需要你手工来写,这样有什么好处?最大的好处就是:只要你的代码编译通过,那么就能生成正确的SQL语句,而不是报运行时错误,然后让你去检查SQL语句。
当然,好处不止这个,还有如:简单,开发快捷,更灵活的where从句生成等。
11、前面说了,LINQ to SQL其实是“聪明”地帮你生成查询语句,但你不能完全相信它,因为它有时候是“自作聪明”,所以你要在调试的时候看看它究竟干了些什么。我的方法是将它的生成的SQL语句打印到Debug窗口中,这个小技巧帮我找到了不少的问题,OK,这里我把我写的这个小小的DataContext的帮助类贴出来:
12、public class DebugWriter : TextWriter
{
public override void WriteLine(string value)
{
Debug.WriteLine(value);
}
public override void WriteLine(string format, params object[] arg)
{
Debug.WriteLine(format, arg);
}
public override Encoding Encoding
{
get { return Encoding.UTF8; }
}
}
public static class DataContextHelper
{
public static void InitForModification(this DataContext dc)
{
dc.DeferredLoadingEnabled = false;
#if DEBUG
dc.Log = new DebugWriter();
#endif
}
/// <summary>
/// 如果一个表中的某一列引用到别的表,默认情况下LINQ to SQL会在遍历搜索结果的时候
/// 动态地去获取别的表的内容,这样就可能产生大量的SQL查询
/// 当把DeferredLoadingEnabled设置为false之后,LINQ to SQL则关闭这项功能,省去了大量的开销
/// 事实上,我们更多的时候会用到LoadWith,直接生成一条联表查询
/// </summary>
public static void InitForQuery(this DataContext dc)
{
dc.ObjectTrackingEnabled = false;
dc.DeferredLoadingEnabled = false;
#if DEBUG
dc.Log = new DebugWriter();
#endif
}
public static DateTime GetDbDateTime(this DataContext dc)
{
try
{
return dc.ExecuteQuery<DateTime>("SELECT GETDATE()").Single();
}
catch (Exception ex)
{
throw new Exception("Database error.", ex); //建议替换成你的自定义异常类型
}
}
}
13、InitForQuery - 用于查询(注意看看我写的那几行注释,后面会提到)
InitForModification - 用于增删改
GetDbDateTime - 由于LINQ to SQL不直接支持GetDate函数,所以写一个函数来获取DBMS的时间