通过前面MikeTaulty的讲解,我对LINQ的使用有个大概的感观认识,下面再来看看Scottgu在asp.net中的例子.(其实LINQ只和后台有关,很表现层没有关系的)
Demo1:
1. 同样地我们在创建网站后,添加一个dbml文件NorthwindDemo1.dbml(dbml是Database Markup Language,是一个标准的XML文件,其实可以把他看作是一个生成映射的中间文件,因为我们生成的实体类时候,有的是VB,是C#,或者其他的)
用VS自带的可视化的O/R Mapping工具,可以通过简单的拖拉,生成dbml.,demo1的结构如下:
dbml文件源码如下:
< Database Name ="E:VS2008LINQ学习TESTCODELINQTEST2_WEB_SCOTTGUAPP_DATANORTHWND.MDF" Class ="NorthwindDataContext" xmlns ="http://schemas.microsoft.com/linqtosql/dbml/2007" >
< Connection Mode ="WebSettings" ConnectionString ="Data Source=.SQLEXPRESS;AttachDbFilename=|DataDirectory|NORTHWND.MDF;Integrated Security=True;Connect Timeout=30;User Instance=True" SettingsObjectName ="System.Configuration.ConfigurationManager.ConnectionStrings" SettingsPropertyName ="NORTHWNDConnectionString" Provider ="System.Data.SqlClient" />
< Table Name ="dbo.Categories" Member ="Categories" >
< Type Name ="Categories" >
< Column Name ="CategoryID" Type ="System.Int32" DbType ="Int NOT NULL IDENTITY" IsPrimaryKey ="true" IsDbGenerated ="true" CanBeNull ="false" />
< Column Name ="CategoryName" Type ="System.String" DbType ="NVarChar(15) NOT NULL" CanBeNull ="false" />
< Column Name ="Description" Type ="System.String" DbType ="NText" CanBeNull ="true" UpdateCheck ="Never" />
< Column Name ="Picture" Type ="System.Byte[]" DbType ="Image" CanBeNull ="true" UpdateCheck ="Never" />
< Association Name ="Categories_Products" Member ="Products" OtherKey ="CategoryID" Type ="Products" />
</ Type >
</ Table >
< Table Name ="dbo.Products" Member ="Products" >
< Type Name ="Products" >
< Column Name ="ProductID" Type ="System.Int32" DbType ="Int NOT NULL IDENTITY" IsPrimaryKey ="true" IsDbGenerated ="true" CanBeNull ="false" />
< Column Name ="ProductName" Type ="System.String" DbType ="NVarChar(40) NOT NULL" CanBeNull ="false" />
< Column Name ="SupplierID" Type ="System.Int32" DbType ="Int" CanBeNull ="true" />
< Column Name ="CategoryID" Type ="System.Int32" DbType ="Int" CanBeNull ="true" />
< Column Name ="QuantityPerUnit" Type ="System.String" DbType ="NVarChar(20)" CanBeNull ="true" />
< Column Name ="UnitPrice" Type ="System.Decimal" DbType ="Money" CanBeNull ="true" />
< Column Name ="UnitsInStock" Type ="System.Int16" DbType ="SmallInt" CanBeNull ="true" />
< Column Name ="UnitsOnOrder" Type ="System.Int16" DbType ="SmallInt" CanBeNull ="true" />
< Column Name ="ReorderLevel" Type ="System.Int16" DbType ="SmallInt" CanBeNull ="true" />
< Column Name ="Discontinued" Type ="System.Boolean" DbType ="Bit NOT NULL" CanBeNull ="false" />
< Association Name ="Categories_Products" Member ="Categories" ThisKey ="CategoryID" Type ="Categories" IsForeignKey ="true" />
</ Type >
</ Table >
</ Database >
我们可以看到,里面的内容也很好理解,主要标记了要生成的表和字段的一些属性和关系,现在主要是感受使用,就先不考究他了.
2. 我们在页面中添加一个GridView做数据输出,后台我们只是做一个简单的select,然后绑定输出,在Page_Load中添加如下代码:
var query = from p in NwCtx.Products
select p;
// 在这里我们可以看出,其实这个query返回的是一个数据集,可以作为数据源绑定输出
GridViewDemo1.DataSource = query;
GridViewDemo1.DataBind();
结果输出:
后台执行的SQL同样简单:
FROM [ dbo ] . [ Products ] AS [ t0 ]
当然我可以加上查询的条件:
如:
where p.Categories.CategoryName.StartsWith( " C " )
select p;
又如:
where p.Categories.Products.Count > 5
select p;
当然我们还可以重编输出的内容和加上一些运算输出,如:
where p.Categories.Products.Count > 5
select new
... {
p.ProductID,
p.ProductName
} ;
又如:
where p.Categories.Products.Count > 5
select new
... {
产品ID = p.ProductID,
产品名字 = p.ProductName,
总数 = p.Order_Details.Sum(o => o.Quantity),
总收入 = p.Order_Details.Sum(o => o.Quantity * o.UnitPrice)
} ;
SELECT SUM ( CONVERT ( Int , [ t3 ] . [ Quantity ] ))
FROM [ dbo ] . [ Order Details ] AS [ t3 ]
WHERE [ t3 ] . [ ProductID ] = [ t0 ] . [ ProductID ]
) AS [ value ] , (
SELECT SUM (( CONVERT ( Decimal ( 29 , 4 ), [ t4 ] . [ Quantity ] )) * [ t4 ] . [ UnitPrice ] )
FROM [ dbo ] . [ Order Details ] AS [ t4 ]
WHERE [ t4 ] . [ ProductID ] = [ t0 ] . [ ProductID ]
) AS [ value2 ]
FROM [ dbo ] . [ Products ] AS [ t0 ]
WHERE ((
SELECT COUNT ( * )
FROM [ dbo ] . [ Categories ] AS [ t1 ] , [ dbo ] . [ Products ] AS [ t2 ]
WHERE ( [ t1 ] . [ CategoryID ] = [ t0 ] . [ CategoryID ] ) AND ( [ t2 ] . [ CategoryID ] = [ t1 ] . [ CategoryID ] )
)) > 5
注意,此时要在dbml里面加入两张表,不然会出错哦:
写着这些语句,刚开始我有些奇怪,为什么不直接按着T-SQL的习惯,把Select语句写到前面呢?查了一下资料,据说是MS为了IDE的智能感应而作出的变化,因为当我们没有写from语句前,是很难知道要select的到底是什么类型,那么就很难能做到代码提醒了,呵呵.
刚才说到query返回的是一个数据集,那么我们就可以对他进行进一步的抽取数据,例如我们可以利用LINQ提供的匿名类对它进行一些操作:
如支取前面十条数据:
结果:
又如取11到20的数据:
只要简单的加上Skip就可以了,当中有个原则,每次返回都是一个数据集,而再下一层操作都是在上一层数据集里面再抽取一个数据集.
结果:
看看使用SQL的变化,就更容易理解这一点:
单纯的query:
SELECT SUM ( CONVERT ( Int , [ t3 ] . [ Quantity ] ))
FROM [ dbo ] . [ Order Details ] AS [ t3 ]
WHERE [ t3 ] . [ ProductID ] = [ t0 ] . [ ProductID ]
) AS [ value ] , (
SELECT SUM (( CONVERT ( Decimal ( 29 , 4 ), [ t4 ] . [ Quantity ] )) * [ t4 ] . [ UnitPrice ] )
FROM [ dbo ] . [ Order Details ] AS [ t4 ]
WHERE [ t4 ] . [ ProductID ] = [ t0 ] . [ ProductID ]
) AS [ value2 ]
FROM [ dbo ] . [ Products ] AS [ t0 ]
WHERE ((
SELECT COUNT ( * )
FROM [ dbo ] . [ Categories ] AS [ t1 ] , [ dbo ] . [ Products ] AS [ t2 ]
WHERE ( [ t1 ] . [ CategoryID ] = [ t0 ] . [ CategoryID ] ) AND ( [ t2 ] . [ CategoryID ] = [ t1 ] . [ CategoryID ] )
)) > 5
加上skip和take:
FROM (
SELECT ROW_NUMBER() OVER ( ORDER BY [ t3 ] . [ ProductID ] , [ t3 ] . [ ProductName ] , [ t3 ] . [ value ] , [ t3 ] . [ value2 ] ) AS [ ROW_NUMBER ] , [ t3 ] . [ ProductID ] AS [ 产品ID ] , [ t3 ] . [ ProductName ] AS [ 产品名字 ] , [ t3 ] . [ value ] AS [ 总数 ] , [ t3 ] . [ value2 ] AS [ 总收入 ]
FROM (
SELECT [ t0 ] . [ ProductID ] , [ t0 ] . [ ProductName ] , (
SELECT SUM ( CONVERT ( Int , [ t1 ] . [ Quantity ] ))
FROM [ dbo ] . [ Order Details ] AS [ t1 ]
WHERE [ t1 ] . [ ProductID ] = [ t0 ] . [ ProductID ]
) AS [ value ] , (
SELECT SUM (( CONVERT ( Decimal ( 29 , 4 ), [ t2 ] . [ Quantity ] )) * [ t2 ] . [ UnitPrice ] )
FROM [ dbo ] . [ Order Details ] AS [ t2 ]
WHERE [ t2 ] . [ ProductID ] = [ t0 ] . [ ProductID ]
) AS [ value2 ] , [ t0 ] . [ CategoryID ]
FROM [ dbo ] . [ Products ] AS [ t0 ]
) AS [ t3 ]
WHERE ((
SELECT COUNT ( * )
FROM [ dbo ] . [ Categories ] AS [ t4 ] , [ dbo ] . [ Products ] AS [ t5 ]
WHERE ( [ t4 ] . [ CategoryID ] = [ t3 ] . [ CategoryID ] ) AND ( [ t5 ] . [ CategoryID ] = [ t4 ] . [ CategoryID ] )
)) > 5
) AS [ t6 ]
WHERE [ t6 ] . [ ROW_NUMBER ] > 10