都说LINQ(Language Integrated Query)是.NET 3.5中最酷的特性。今天在Visual Studio 2008 Express里尝试了一下,感觉十分震撼!
首先简单地说一下LINQ是干什么的:
- 在任何数据源上高效地表达查询行为;
- 将查询结果转换或形成任何形式的结果集;
- 非常方便地操作这个结果集。
对LINQ这个概念不熟悉的同学可以先看这个例子:
using System;
using System.Collections.Generic;
using System.Linq;
namespace SimpleLinq
{
class Program
{
static void Main(string[] args)
{
int[] dataSource = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
IEnumerable<int> lessThan5 = from number in dataSource
where number > 2 && number < 8
orderby number descending
select number;
foreach(int number in lessThan5)
{
Console.WriteLine(number.ToString());
}
Console.ReadLine();
}
}
}
输出结果:
7
6
5
4
3
关键就是这一句:from number in dataSource where number > 2 && number < 8 orderby number descending select number。顾名思义即可,无需多说。
下面是想要演示的LINQ to SQL和ORM(Object-relational mapping)。
1. 打开Visual Web Developer 2008(没有的在这里下载),新建一个网站:
2. 然后将SQL Server 2000的示例数据库NorthWind放到App_Data目录下(没有这个数据库的到这里下载):
3. 下面在App_Code文件夹里创建一个Northwind.dbml文件,这个文件用来包含LINQ to SQL的data model,即一些ORM的信息。
4. 下面生成Northwind数据库的data model,在Database Explorer中将Products和Supliers两张表拖入Northwind.dbml的设计视图即可。注意两张表之间存在一定的关系:
5. 在Default.aspx中创建一个GridView,用来显示数据:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>LINQ to SQL</title>
</head>
<body>
<form id="form" runat="server">
<div>
<asp:GridView ID="gridView" runat="server" />
</div>
</form>
</body>
</html>
6. 在Default.aspx.cs中,我们把符合条件的那些Product查出来(查询条件是Product的Suplier位于USA),查询结果按照ProductName字段的字母顺序排序,然后把结果绑定到GridView:
using System;
using System.Linq;
using System.Web.UI;
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
NorthwindDataContext northwind = new NorthwindDataContext();
gridView.DataSource = from product in northwind.Products where product.Supplier.Country == "USA" orderby product.ProductName select product;
gridView.DataBind();
}
}
请注意这一句:where product.Supplier.Country == "USA"。
至此已经大功告成,运行Default.aspx可以看到结果。整个过程中没有写任何SQL语句来查询数据,甚至没有给出数据库的连接字符串!
可能有的同学会关心查询具体是如何实现的。通过设置断点,可以看到运行时的查询实现:
实现查询的SQL语句为:
{SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID], [t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock], [t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued]
FROM [dbo].[Products] AS [t0]
LEFT OUTER JOIN [dbo].[Suppliers] AS [t1] ON [t1].[SupplierID] = [t0].[SupplierID]
WHERE [t1].[Country] = @p0
ORDER BY [t0].[ProductName]
}
而连接字符串自动加入到了web.config文件中:
<connectionStrings>
<add name="NORTHWNDConnectionString" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\NORTHWND.MDF;Integrated Security=True;User Instance=True" providerName="System.Data.SqlClient" />
</connectionStrings>
现在网站中的文件如下:
其中Northwind.dbml包含了ORM的映射配置,包括数据库,连接字符串,表,字段,表间关系(比如外键)等的信息:
<?xml version="1.0" encoding="utf-8"?>
<Database Name="NORTHWND" Class="NorthwindDataContext" xmlns="http://schemas.microsoft.com/linqtosql/dbml/2007">
<Connection Mode="WebSettings" ConnectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\NORTHWND.MDF;Integrated Security=True;User Instance=True" SettingsObjectName="System.Configuration.ConfigurationManager.ConnectionStrings" SettingsPropertyName="NORTHWNDConnectionString" Provider="System.Data.SqlClient" />
<Table Name="dbo.Suppliers" Member="Suppliers">
<Type Name="Supplier">
<Column Name="SupplierID" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
<Column Name="CompanyName" Type="System.String" DbType="NVarChar(40) NOT NULL" CanBeNull="false" />
<Column Name="ContactName" Type="System.String" DbType="NVarChar(30)" CanBeNull="true" />
<Column Name="ContactTitle" Type="System.String" DbType="NVarChar(30)" CanBeNull="true" />
<Column Name="Address" Type="System.String" DbType="NVarChar(60)" CanBeNull="true" />
<Column Name="City" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" />
<Column Name="Region" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" />
<Column Name="PostalCode" Type="System.String" DbType="NVarChar(10)" CanBeNull="true" />
<Column Name="Country" Type="System.String" DbType="NVarChar(15)" CanBeNull="true" />
<Column Name="Phone" Type="System.String" DbType="NVarChar(24)" CanBeNull="true" />
<Column Name="Fax" Type="System.String" DbType="NVarChar(24)" CanBeNull="true" />
<Column Name="HomePage" Type="System.String" DbType="NText" CanBeNull="true" UpdateCheck="Never" />
<Association Name="Supplier_Product" Member="Products" OtherKey="SupplierID" Type="Product" />
</Type>
</Table>
<Table Name="dbo.Products" Member="Products">

</Table>
</Database>
注意<Association>定义了两张表之间的关系。
Northwind.dbml.layout是设计视图的信息。而Northwind.designer.cs包含了为ORM自动生成的一系列object的定义,比如前面用到的和Northwind数据库对应的NorthwindDataContext类,以及和Products表对应的Product类,和Suppliers数据库对应的Supplier类:
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.1433
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
[System.Data.Linq.Mapping.DatabaseAttribute(Name = "NORTHWND")]
public partial class NorthwindDataContext : System.Data.Linq.DataContext
{
private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource();
#region Extensibility Method Definitions
partial void OnCreated();
partial void InsertProduct(Product instance);
partial void UpdateProduct(Product instance);
partial void DeleteProduct(Product instance);
partial void InsertSupplier(Supplier instance);
partial void UpdateSupplier(Supplier instance);
partial void DeleteSupplier(Supplier instance);
#endregion

}
[Table(Name = "dbo.Products")]
public partial class Product : INotifyPropertyChanging, INotifyPropertyChanged
{
private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
private int _ProductID;
private string _ProductName;
private System.Nullable<int> _SupplierID;
private System.Nullable<int> _CategoryID;
private string _QuantityPerUnit;
private System.Nullable<decimal> _UnitPrice;
private System.Nullable<short> _UnitsInStock;
private System.Nullable<short> _UnitsOnOrder;
private System.Nullable<short> _ReorderLevel;
private bool _Discontinued;
private EntityRef<Supplier> _Supplier;
#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnProductIDChanging(int value);
partial void OnProductIDChanged();
partial void OnProductNameChanging(string value);
partial void OnProductNameChanged();
partial void OnSupplierIDChanging(System.Nullable<int> value);
partial void OnSupplierIDChanged();
partial void OnCategoryIDChanging(System.Nullable<int> value);
partial void OnCategoryIDChanged();
partial void OnQuantityPerUnitChanging(string value);
partial void OnQuantityPerUnitChanged();
partial void OnUnitPriceChanging(System.Nullable<decimal> value);
partial void OnUnitPriceChanged();
partial void OnUnitsInStockChanging(System.Nullable<short> value);
partial void OnUnitsInStockChanged();
partial void OnUnitsOnOrderChanging(System.Nullable<short> value);
partial void OnUnitsOnOrderChanged();
partial void OnReorderLevelChanging(System.Nullable<short> value);
partial void OnReorderLevelChanged();
partial void OnDiscontinuedChanging(bool value);
partial void OnDiscontinuedChanged();
#endregion

}
[Table(Name = "dbo.Suppliers")]
public partial class Supplier : INotifyPropertyChanging, INotifyPropertyChanged
{

}
可以看出,LINQ to SQL提供了一种超酷的方法来实现ORM和数据访问层。用Scott Guthrie的话来说,LINQ很酷的地方在于,LINQ是强类型的。这意味着:
- 查询会在编译时进行检查,这意味着在开发时就可以检查代码的正确性,而不是像SQL语句,到运行时才会发现错误;
- 能够在IDE中获得智能感知的提示,这不仅加快了编码速度,而且使复杂的集合和数据源对象模型更容易处理。
注: