精通LINQ数据访问技术
1. C#的lINQ怎么用干什么用的
1.LINQ:Language Integrated Query 语言集成查询。
2.LINQ通过对象的方式对数据库进行描述。
3.LINQ是一种能够快速对大部分数据源进行访问和数据整合的一种技术,使用相同的基本查询表达式模式类查询和转换sql数据库、ADO.NET数据集、XML文档和流已经.NET集合中的数据。
4.使用方法:
LINQ to Objects
LINQ to DataSet
LINQ to SQL
LINQ to Entities
LINQ to XML
2. LINQ的原理浅析
LINQ(Language Integrated Query)是Visual Studio 2008中的领军人物。借助于LINQ技术,我们可以使用一种类似SQL的语法来查询任何形式的数据。目前为止LINQ所支持的数据源有SQL Server、Oracle、XML(标准通用标记语言下的一个应用)以及内存中的数据集合。开发人员也可以使用其提供的扩展框架添加更多的数据源,例如MySQL、Amazon甚至是GoogleDesktop。
一般来讲,这类查询语句的一个重要特点就是可以并行化执行。虽然有些情况下并行可能会带来一些问题,但这种情况非常少见。这样也就水到渠成地引出了PLINQ这个并行处理的LINQ类库。
PLINQ原名为Parallel LINQ,支持XML和内存中的数据集合。执行于远程服务器上的查询语句(例如LINQ to SQL)显然无法实现这个功能。
将LINQ语句转换为PLINQ语句极为简单——只需要在查询语句中From子句所指定的数据源的最后添加.AsParallel()即可。随后Where、OrderBy和Select子句将自动改为调用这个并行的LINQ版本。
据MSDN Magazine介绍,PLINQ可以以三种方式执行。第一种是管道处理:一个线程用来读取数据源,而其他的线程则用来处理查询语句,二者同步进行——虽然这个单一的消费线程可能并不那么容易与多个生产线程同步。不过若是能够仔细配置好负载平衡的话,仍然会极大地减少内存占用。
第二种模式叫做“stop and go”,用于处理结果集需要被一次返回时(例如调用ToList、ToArray或对结果排序)的情况。在这种模式下,将依次完成各个处理过程,并将结果统一返回给消费线程。这个模式在性能上将优于第一种模式,因为它省去了用来保持线程同步所花费的开销。
最后一种方法叫做“inverted enumeration”。该方法并不需要实现收集到所有的输出,然后在单一的线程中处理,而是将最终调用的函数通过ForAll扩展传递到每个线程中。这是目前为止最快的一种处理模式,不过这需要传递到ForAll中的函数是线程安全的,且最好不包含任何lock之类的互斥语句。
若是PLINQ中任意的一个线程抛出异常,那么所有的其他线程将会被终止。若是抛出了多个异常,那么这些异常将被组合成一个MultipleFailuresException类型的异常,但每个异常的调用堆栈仍会被保留。
3. 什么是linq技术
LINQ,语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展。它允许编写C#或者Visual Basic代码以查询数据库相同的方式操作内存数据。
从技术角度而言,LINQ定义了大约40个查询操作符,如select、from、in、where以及order by(C#中)。使用这些操作符可以编写查询语句。不过,这些查询还可以基于很多类型的数据,每个数据类型都需要一个单独的LINQ类型。
经过了最近 20 年,面向对象编程技术( object-oriented (OO) programming technologies )在工业领域的应用已经进入了一个稳定的发展阶段。程序员现在都已经认同像 类(classes)、对象(objects)、方法(methods)这样的语言特性。考察现在和下一代的技术,一个新的编程技术的重大挑战开始呈现出来,即面向对象技术诞生以来并没有解决降低访问和整合信息数据( accessing and integrating information )的复杂度的问题。其中两个最主要访问的数据源与数据库(database)和XML(标准通用标记语言下的一个应用)相关。
LINQ 提供了一条更常规的途径即给.Net Framework添加一些可以应用于所有信息源( all sources of information )的具有多种用途( general-purpose )的语法查询特性( query facilities ),这是比向开发语言和运行时( runtime )添加一些关系数据( relational )特性或者类似 XML 特性( XML-specific )更好的方式。这些语法特性就叫做 .NET Language Integrated Query (LINQ) 。
4. 谁有关于linq的资料,急需
在达人博客上看到的:是个系列,一共三篇,你去网络搜搜“LINQ to SQL、NHibernate比较”就能找到了。我给你转第一篇。
LINQ to SQL、NHibernate比较(一)-- LINQ和NHibernate初体验
1 引言
研发与数据库打交道的系统的时候,最过于繁琐的莫过于没有编程快感的使用ADO.NET对后台数据库进行操作,因为所有的数据库连接、读取、操作千篇一律,编程成为了体力活。
虽然我们可以设计自己的类作为数据库访问的持久层,但是每一个类都必须有不相同的SQL语句,这样对于设计统一的数据库读写类造成了很大的困难。
开发人员在这种情况下必须包办窗体设计、方法设计、数据库读写设计的过程,这样加大了开发人员的负担也使得项目的维护和后期开发变得难以进行。
2 .NET下的ORM解决方案
2.1 LINQ
2.1.1 LINQ简介
作为微软开发的查询方案,LINQ 提供了一条更常规的途径即给 .Net Framework 添加一些可以应用于所有信息源( all sources of information )的具有多种用途( general-purpose )的语法查询特性( query facilities ),这是比向开发语言和运行时( runtime )添加一些关系数据( relational )特性或者类似 XML 特性( XML-specific )更好的方式。这些语法特性就叫做 .NET Language Integrated Query (LINQ) 。
如果觉得上面的解释有点抽象,那么可以这样理解,LINQ其实就是提供了一套查询功能,可以实现任何数据源的查询,此处数据源不单指数据库或者XML文件,而是任何集合或者实体,比如我们接触各种编程语言都需要用到的数组,现在不用遍历数组元素来寻找需要的项,LINQ可以实现这方面的查询。
LINQ查询数组:
图2.1 LINQ查询数组
上面是最简单的LINQ实现对数组的查询,泛型类型var在LINQ查询中提供了强大的委托类型支持,不管查询集合中项的类型(无论是int,char还是string或者类),我们只用一个var就可以保存LINQ查询到的结果。程序结果如下:
图2.2 LINQ查询数组程序结果
是不是很方便,LINQ的应用远远不这些,通过不同的映射方案,我们可以实现对数据库(LINQ To SQL),对XML文件(LINQ To XML)的访问。
2.1.2 LINQ简介
表2.1 LINQ的操作符
操作符
说明
聚合
Aggregate
对序列执行一个自定义方法
Average
计算数值序列的平均值
Count
返回序列中的项目数(整数)
LongCount
返回序列中的项目数(长型)
Min
查找数字序列中的最小数
Max
查找数字序列中的最大数
Sum
汇总序列中的数字
连接
Concat
将两个序列连成一个序列
转换
Cast
将序列中的元素转换成指定类型
OfType
筛选序列中指定类型的元素
ToArray
从序列返回一个数组
ToDictionary
从序列返回一个字典
ToList
从序列返回一个列表
ToLookup
从序列返回一个查询
ToSequence
返回一个 IEnumerable 序列
元素
DefaultIfEmpty
为空序列创建默认元素
ElementAt
返回序列中指定索引的元素
ElementAtOrDefault
返回序列中指定索引的元素,或者如果索引超出范围,则返回默认值
First
返回序列中的第一个元素
FirstOrDefault
返回序列中的第一个元素,或者如果未找到元素,则返回默认值
Last
返回序列中的最后一个元素
LastOrDefault
返回序列中的最后一个元素,或者如果未找到元素,则返回默认值
Single
返回序列中的单个元素
SingleOrDefault
返回序列中的单个元素,或者如果未找到元素,则返回默认值
相等
SequenceEqual
比较两个序列看其是否相等
生成
Empty
生成一个空序列
Range
生成一个指定范围的序列
Repeat
通过将某个项目重复指定次数来生成一个序列
分组
GroupBy
按指定分组方法对序列中的项目进行分组
联接
GroupJoin
通过归组将两个序列联接在一起
Join
将两个序列从内部联接起来
排序
OrderBy
以升序按值排列序列
OrderByDescending
以降序按值排列序列
ThenBy
升序排列已排序的序列
ThenByDescending
降序排列已排序的序列
Reverse
颠倒序列中项目的顺序
分区
Skip
返回跳过指定数目项目的序列
SkipWhile
返回跳过不满足表达式项目的序列
Take
返回具有指定数目项目的序列
TakeWhile
返回具有满足表达式项目的序列
投影
Select
创建部分序列的投影
SelectMany
创建部分序列的一对多投影
限定符
All
确定序列中的所有项目是否满足某个条件
Any
确定序列中是否有任何项目满足条件
Contains
确定序列是否包含指定项目
限制
Where
筛选序列中的项目
设置
Distinct
返回无重复项目的序列
Except
返回代表两个序列差集的序列
Intersect
返回代表两个序列交集的序列
Union
返回代表两个序列交集的序列
Lambda 表达式
许多标准查询操作符在对序列执行运算时都使用 Func 委托来处理单个元素。Lambda 表达式可与标准查询操作符结合使用以代表委托。lambda 表达式是创建委托实现的简略表达形式,并可用于匿名委托适用的所有场合。C# 和 Visual Basic® .NET 均支持 Lambda 表达式。但是,必须注意:由于 Visual Basic .NET 尚不支持匿名方法,Lambda 表达式可能仅包含一个语句。
上例中的的程序等同于下面
图2.3 Lambda表达式的使用
2.2 NHibernate
说到NHibernate,就不得不提Hibernate,原因很简单,Hibernate顾名思义就是Hibernate的.NET版本。
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。
NHibernate作为Hibernate的.NET应用于Hibernate的实现完全相同,学习NHibernate完全可以直接学习Hibernate的资料。
事实上,虽然在Java数据库映射领域Hibernate是使用最为广泛的方案,但是在.NET中由于LINQ等映射方案(包括微软下一代重量级的Entity Framework)的使用,NHibernate冷了许多。
NHibernate需要配置数据库配置文件和类/表映射配置文件,所以使用NHibernate需要懂得XML文件的基础知识,并且需要掌握比较复杂的XML文件配置节和相应的配置命令。
2.2.1 数据库配置文件
NHibernate官方提供了配置文件的模板和实例可供我们参考。
图2.4 NHibernate官方数据库配置文件模板(对应了不同的数据库)
上图为数据库配置文件。通常以“cfg.xml”作为后缀,一个示例的文件内容如下
图2.5 数据库配置文件示例
下面是一些在运行时可以改变NHibernate行为的其他配置。所有这些都是可选的,也有合理的默认值。
表2.2 NHibernate 配置属性
属性名
用途
hibernate.dialect
NHibernate方言(Dialect)的类名 - 可以让NHibernate使用某些特定的数据库平台的特性
例如: full.classname.of.Dialect(如果方言创建在NHibernate中), 或者full.classname.of.Dialect, assembly (如果使用一个自定义的方言的实现,它不属于NHibernate)。
hibernate.default_schema
在生成的SQL中,scheml/tablespace的全限定名.
例如: SCHEMA_NAME
hibernate.prepare_sql
是否准备sql语句
例如: true | false
hibernate.session_factory_name
SessionFactory被创建后将自动绑定这个名称.
例如: some.name
hibernate.use_outer_join
允许使用外连接抓取。
例如:true | false
hibernate.cache.provider_class
指定一个自定义的CacheProvider缓存提供者的类名
例如: full.classname.of.CacheProvider(如果ICacheProvider创建在NHibernate中), 或full.classname.of.CacheProvider, assembly(如果使用一个自定义的ICacheProvider,它不属于NHibernate)。
hibernate.query.substitutions
把NHibernate查询中的一些短语替换为SQL短语(比如说短语可能是函数或者字符)。
例如: hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC
2.2.2 实体映射配置文件
NHibernate官方开源包中提供了实体映射配置文件的实例可供我们参考。
图2.6 NHibernate开源包中提供的实体映射配置文件
与数据库配置文件一样实体映射配置文件也是XML文件(XML果然是很强大啊,微软下一代应用程序开发技术WPF就是使用XML文件将C/S和B/S长期分居的二人统一到一个屋檐下),所不同的是实体映射配置文件后缀是“hbm.xml”。
图2.7 实体映射配置文件
实体映射配置文件所要配置的信息一般为
Ø Schema
所有的XML映射都需要使用nhibernate-mapping-2.0 schema。目前的schema可以在NHibernate的资源路径或者是NHibernate.dll的嵌入资源(Embedded Resource)中找到。NHibernate总是会优先使用嵌入在资源中的schema文件。
Ø hibernate-mapping
(1)
schema (可选): 数据库schema名称.
(2)
default-cascade (可选 - 默认为 none): 默认的级联风格.
(3)
auto-import (可选 - 默认为 true): 指定是否我们可以在查询语言中使用非全限定的类名(仅限于本映射文件中的类)。
(4)
default-access (可选 - 默认为 property): NHibernate访问属性值时的策略。
(5)
assembly (可选): 指定一个程序集,如果在映射文档中没有指定程序集,就使用这个程序集。
(6)
namespace (可选): 指定一个命名空间前缀,如果在映射文档中没有指定全限定名,就使用这个命名空间名。
Ø class (1)
name: 持久化类(或者接口)的全限定名。
(2)
table: 对应的数据库表名。
(3)
discriminator-value (可选 - 默认和类名一样): 一个用于区分不同的子类的值,在多态行为时使用。
(4)
mutable (可选, 默认为 true): 表明该类的实例可变(不可变)。
(5)
schema (可选): 覆盖在根<hibernate-mapping> 元素中指定的schema名字。
(6)
proxy (可选): 指定一个接口,在延迟装载时作为代理使用。你可以在这里使用该类自己的名字。
(7)
dynamic-update (可选, 默认为 false): 指定用于UPDATE 的SQL将会在运行时动态生成,并且只更新那些改变过的字段。
(8)
dynamic-insert (可选, 默认为 false): 指定用于INSERT的 SQL 将会在运行时动态生成,并且只包含那些非空值字段。
(9)
polymorphism (可选, 默认为 implicit(隐式)): 界定是隐式还是显式的使用查询多态。
(10)
where (可选) 指定一个附加的SQL WHERE 条件,在抓取这个类的对象时会一直增加这个条件。
(11)
persister (可选): 指定一个定制的 IClassPersister.
(12)
lazy(可选):假若设置 lazy="true",就是设置这个类自己的名字作为proxy接口的一种等价快捷形式。
Ø id (1)
name (可选): 标识属性的名字。
(2)
type (可选): 标识NHibernate类型的名字。
(3)
column (可选 - 默认为属性名): 主键字段的名字。
(4)
unsaved-value (可选 - 默认为 null): 一个特定的标识属性值,用来标志该实例是刚刚创建的,尚未保存。这可以把这种实例和从以前的session中装载过(可能又做过修改--译者注)但未再次持久化的实例区分开来。
(5)
access (可选 - 默认为 property): NHibernate用来访问属性值的策略。
除此之外我们可以通过其他途径深入了解配置方面的知识,一个NHibernate项目,配置文件的错误往往导致错误的结果甚至使得程序无法运行。
3 小结
本文初步介绍了LINQ to SQL和NHibernate,其中介绍NHibernate使用了较多的篇幅,因为相对LINQ to SQL而言NHibernate的使用入门门槛较高,配置较为复杂。关于LINQ to SQL、NHibernate优缺点将在后面文章中讨论,不过从此处其实已经得出一点,那就是LINQ to SQL比NHibernate更加容易上手,节省了人员培训的开销。
5. 如何使用LINQ链接数据库并操作数据库
之前在远标做过用JAVA连接数据库主要有两种方式,一是用JDBC-ODBC桥来连接,二是用相关厂商提供的相应驱动程序来连接,首先谈谈第一种连接。
JDBC-ODBC桥接器是用JdbcOdbc.Class和一个用于访问ODBC驱动程序的本地库实现的。对于WINDOWS平台,该本地库是一个动态连接库DLL(JDBCODBC.DLL)。
由于JDBC在设计上与ODBC很接近。在内部,这个驱动程序把JDBC的方法映射到ODBC调用上,这样,JDBC就可以和任何可用的ODBC驱动程序进行交互了。这种桥接器的优点是,它使JDBC目前有能力访问几乎所有的数据库。通行方式如图所示:
应用程序---JDBC API---JDBC-ODBC---ODBC API---ODBC层---数据源
具体操作方法为:
首先打开控制面板的管理工具,打开数据源(ODBC),在用户DSN里面添加数据源(即你要连接的数据库的名字),在这里假定连接SQL SERVER 2000的GoodsSupply数据库。名称填写你要连接的数据库的名称(GoodsSupply),然后逐步设置,如果选用了使用SQL-SERVER密码认证的话,就要输入相应的用户名及密码连接到数据库。一路下一步设置完成。
在JAVA里面编写程序进行测试,在这里我的程序是让用户输入任意的表名与与列名,把该列的所有数据输出。源代码如下:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.sql.*;
public class ODBCBridge {
public static void main(String[] args) {
String url="jdbc:odbc:GoodsSupply";
Statement sm=null;
String command=null;
ResultSet rs=null;
String tableName=null;
String cName=null;
String result=null;
BufferedReader input=new BufferedReader(new InputStreamReader(System.in));
try {
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //加载驱动
}catch(ClassNotFoundException e){
System.out.println("Can not load Jdbc-Odbc Bridge Driver");
System.err.print("ClassNotFoundException:");
System.err.println(e.getMessage());
}
Connection con=DriverManager.getConnection(url,"USER","PASSWORD"); //使用SQL-SERVER2000认证
DatabaseMetaData dmd=con.getMetaData(); //DMD为连接的相应情况
System.out.println("连接的数据库:"+dmd.getURL());
System.out.println("驱动程序:"+dmd.getDriverName());
sm=con.createStatement();
System.out.println("输入表名");
tableName=input.readLine();
while(true) {
System.out.println("输入列名(为空时程序结束):");
cName=input.readLine();
if(cName.equalsIgnoreCase(""))
break;
command="select "+cName+" from "+tableName;
rs=sm.executeQuery(command); //执行查询
if(!rs.next())
System.out.println("表名或列名输入有误");
else {
System.out.println("查询结果为:");
do
{
result=rs.getString(cName);
//数据库语言设置为中文,不用转换编码
//result=new String(result.getBytes("ISO-8859-1"),"GB2312");
System.out.println(result);
}while(rs.next());
}
}
}catch(SQLException ex) {
System.out.println("SQLException:");
while(ex!=null) {
System.out.println("Message:"+ex.getMessage());
ex=ex.getNextException();
}
}catch(Exception e) {
System.out.println("IOException");
}
}
}
6. 为什么要学习使用LINQ技术
首先要知道Linq 都有哪些知识点,这个可以自行网络;
对集合的查询,筛选,排序,重新生成新的对象
多个集合的连接查询
Linq to SQL ,可以进行SQL查询等操作, 可以忽略不同数据库之间的差异;
你要知道很多人不懂得sql语句的,更别说不同数据库的sql语句;
推荐你看一下 ,自己搜索下面的条件
Linq使用心得——SelectMany替代二重foreach循环
可以看得出比你自己写循环要方便很多;
5.推荐你把LINQ的几十个操作符都看一下,知道是什么功能,可以先会用,知道它能干什么,这个时候再具体讨论它的意义,它该不该学习
6.下面是2个网址,有时间可以自行看一下它是什么,然后再深究其学习的意义
http://www.cnblogs.com/foundation/archive/2009/01/05/1369371.html
http://www.cnblogs.com/lyj/archive/2008/03/24/1119671.html