一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

LINQ&EF任我行(一)

 軟件技術(shù)與教學(xué) 2014-06-04

(原創(chuàng):灰灰蟲(chóng)的家http://hi.baidu.com/grayworm)

LinQ家族五大成員:
LinQ to Objects - 默認(rèn)功能,用來(lái)實(shí)現(xiàn)對(duì)內(nèi)存中集合對(duì)象的查詢
LinQ to SQL - 針對(duì)SQL Server的查詢,它是一個(gè)帶有可視化的操作界面的ORM工具
LinQ to DataSet - 對(duì)強(qiáng)類型化或弱類型化的DataSet或獨(dú)立的DataTable進(jìn)行查詢
LinQ to Entity - 對(duì)實(shí)體框架中EDM定義的實(shí)體集合進(jìn)行查詢。
LinQ to XML - 對(duì)XML文檔進(jìn)行查詢創(chuàng)建等操作。


C#語(yǔ)法與LinQ相關(guān)的新增功能


1.隱式強(qiáng)類型變量
在C#3.0中可以使用var關(guān)鍵字隱式定義強(qiáng)類型局部變量。



《圖1》
這里的var關(guān)鍵字定義變量與JavaScript定義變量看起來(lái)很像但二者有著本質(zhì)的區(qū)別。
JavaScript定義的變量是弱類型的變量,也可理解為是一種通用類型的變量,它可以容納各種類型的值,還可以在運(yùn)行過(guò)程中動(dòng)態(tài)修改其中的內(nèi)容類型。下面這種寫法在JavaScript中是正確的:
var obj = 3.14;
obj = "hello world";
C#中的var則是種強(qiáng)類型的變量,它在定義的時(shí)候會(huì)確定數(shù)據(jù)類型,分配內(nèi)存空間。上面這兩名代碼在C#3.0中會(huì)報(bào)錯(cuò),因?yàn)榈谝痪湟呀?jīng)把obj定義為double型的變量,第二句把字符串賦值給double是錯(cuò)誤的操作。

隱式強(qiáng)類型并不能有效簡(jiǎn)化我的書(shū)寫的代碼,但當(dāng)我們?cè)谟盟鼇?lái)動(dòng)態(tài)接收一些未知類型的數(shù)據(jù)的時(shí)候就顯雖得很強(qiáng)大。在隱式強(qiáng)類型變量出現(xiàn)前,我們一般是使用object型變量來(lái)接收這種未知類型的數(shù)據(jù)的。

2.對(duì)象初始化
這個(gè)功能可以有效簡(jiǎn)化類的getter和setter部份的代碼,還可以只使用一行表達(dá)式語(yǔ)句實(shí)現(xiàn)對(duì)象的實(shí)例化與初始化操作。
如定義實(shí)例類時(shí)可以使用如下代碼,沒(méi)有必要再把成員變量和屬性分別定義了。
public class LineItem
{
    public int OrderID { get; set; }
    public int ProductID { get; set; }
    public short Quantity { get; set; }
    public string QuantityPerUnit { get; set; }
    public decimal UnitPrice { get; set; }
    public float Discount { get; set; }
}
實(shí)例化LineItem對(duì)象,并為它賦值
var line3 = new LineItem { OrderID = 11000, ProductID = 61, Quantity = 30, QuantityPerUnit = “12 1-kg cartons”, UnitPrice = 15.55M, Discount = 0.15F };

3.數(shù)組初始化
var LineItems = new[]
{
    new LineItem {OrderID = 11000, ProductID = 11, Quantity = 10,
        QuantityPerUnit = “24 500-g bottles”, UnitPrice = 15.55M, Discount = 0.0F},
    new LineItem {OrderID = 11000, ProductID = 21, Quantity = 20,
        QuantityPerUnit = “12 1-kg cartons”, UnitPrice = 20.2M, Discount = 0.1F},
    new LineItem {OrderID = 11000, ProductID = 31, Quantity = 30,
        QuantityPerUnit = “24 1-kg bags”, UnitPrice = 25.45M, Discount = 0.15F}
};

4.集合初始化
var LineItemsList = new List < LineItem >
{
    new LineItem {OrderID = 11000, ProductID = 11, Quantity = 10,
       QuantityPerUnit = “24 500-g bottles”, UnitPrice = 15.55M, Discount = 0.0F},
    new LineItem {OrderID = 11000, ProductID = 21, Quantity = 20,
       QuantityPerUnit = “12 1-kg cartons”, UnitPrice = 20.2M, Discount = 0.1F},
    new LineItem {OrderID = 11000, ProductID = 31, Quantity = 30,
       QuantityPerUnit = “24 1-kg bags”, UnitPrice = 25.45M, Discount = 0.15F}
};

5.匿名類型
過(guò)去我們要生成對(duì)象時(shí),必須事先定義該對(duì)象的類,然后使用new關(guān)鍵字來(lái)實(shí)例化該類。匿名類型簡(jiǎn)化定義類的這個(gè)過(guò)程,我們可以使用new關(guān)鍵字直接把類的定義,類的實(shí)例化放在一個(gè)表達(dá)式語(yǔ)句中。
如:
var obj = new
{
    Name = "zhangsan",
    Age = 18,
    URL = "
};
Console.WriteLine(obj.Name + obj.Age + obj.URL);

匿名類型主要用在LinQ to SQL中對(duì)字段的投影功能上:
var query = from i in LineItems select new { i.OrderID, i.ProductID, i.UnitPrice }

6.擴(kuò)展方法
擴(kuò)展方法就是為現(xiàn)有的類追加我們自定義的方法。在C#3.0的集成開(kāi)發(fā)環(huán)境中,我們會(huì)發(fā)現(xiàn)帶有向下箭頭的方法,這些方法是我們?cè)贑#2.0中所沒(méi)有見(jiàn)到的方法,這些方法就是我們所謂的“擴(kuò)展方法”,它是C#3.0在C#2.0的基礎(chǔ)上新增的一系列的方法,當(dāng)然我們也可以為內(nèi)置類添加我們自己的主擴(kuò)展方法。



《圖2》
例如在string中有個(gè)Length()擴(kuò)展方法,它用來(lái)取得字符串的長(zhǎng)度,但當(dāng)字符串是null的時(shí)候調(diào)用該字符串的Length()時(shí)候會(huì)拋出異常。下面我們?yōu)镾tring類添加一個(gè)自定義的方法LengthNullable(),如果字符串為null不拋出異常,而返回-1:
代碼如下:
static class ExtensionMethods
{
    public static int LengthNullable(this string test)
    {
        if (test != null)
        {
            return test.Length;
        }
        else
        {
            return -1
        }
    }
}
C#3.0的擴(kuò)展方法需要單獨(dú)寫在一個(gè)public static的類中,并且擴(kuò)展方法也應(yīng)當(dāng)用public static修飾。擴(kuò)展方法的參數(shù)有三部份組成(this string test),第一部份是this關(guān)鍵字,它用來(lái)告訴編譯器該方法是擴(kuò)展方法;第二部份是該方法要追加到哪個(gè)類上,上面的例子代表該LengthNullable方法要追加到string類中去;第三部份是該類的實(shí)例名。
public static class ExtentionMethods
{
     public static void Sleep(this Ren r)
     {
         Console.WriteLine(r.Name+" is sleeping.....");
     }
}
public class Ren
{
     public string Name { get; set; }
     public int Age { get; set; }
     public void Speak()
     {
         Console.WriteLine(Name + Age);
     }
}
如果擴(kuò)展方法與實(shí)例方法重名了,那在調(diào)用的時(shí)候只會(huì)調(diào)用到實(shí)例方法。

7.匿名方法
在C#2.0中就存在匿名方法,但很少有程序員去使用匿名方法,因?yàn)樗恼Z(yǔ)法有些怪異。匿名方法的主要用法:使用代理來(lái)替代一些簡(jiǎn)單的方法。
大家都知道代理是指向方法的指針。如:
//聲明代理
delegate void Delegate(int x);        
//定義方法
void DoSomething(int y) { /* Something */ };        
//把代理指向方法
Delegate d = obj.DoSomething;

這里的方法有方法名--DoSomething,而匿名方法可以讓代理直接指向一個(gè)沒(méi)有名子的方法。如:
//聲明代理
delegate void Delegate(int x);
//把代理指向一個(gè)匿名方法。
Del d = delegate(int y) { /* Do Something */ };

匿名方法可以使代碼變得更緊湊、更清晰、占用更少的資源。由于匿名方法與代理的關(guān)系很密切,所以有的人也稱之為“匿名代理”。
在泛型集合List<T>中就有幾個(gè)方法Exists()、Find()、FindAll()、RemoveAll()等方法,在Array類中也有類似的方法。這些方法都能夠?qū)Ψ盒图线M(jìn)行簡(jiǎn)單的查詢操作,它們的方法簽名如下所示:



《圖3》
每個(gè)方法中都有個(gè)參數(shù)Predicate<T>,這個(gè)參數(shù)是個(gè)泛型代理,用來(lái)篩選數(shù)據(jù)。
如果不使用匿名方法,那我們得這樣編寫代碼:
static bool HighUnitPrice(LineItem i)
{
    if (i.UnitPrice > 25M)
        return true;
    else
        return false;
}
LineItem obj = Array.Find(LineItems, HighUnitPrice);
先定義一個(gè)方法HighUnitPrice(LineItem i),然后在Array.Find()的參數(shù)Predicate<T>中調(diào)用該方法。如果有了匿名方法就不用再單獨(dú)定義HighUnitPrice(LineItem i)方法了。
如:
var anon = LineItemsList.Find(
delegate(LineItem i)
{
   return i.UnitPrice > = 25M;
}

);
在C#3.0中的好多地方都用到了匿名方法,匿名方法是理解Lambda表達(dá)式的基礎(chǔ)。

8. Lambda表達(dá)式
Lambda表達(dá)式就是用很少的代碼來(lái)實(shí)現(xiàn)匿名方法。
語(yǔ)法格式:
參數(shù)列表=>表達(dá)式

下面我們來(lái)看看如何把匿名方法轉(zhuǎn)換為L(zhǎng)ambda表達(dá)式:
匿名方法:
delegate(LineItem i) { return i.UnitPrice >= 25M; }
第一步:刪除關(guān)鍵字delegate,變?yōu)?/strong>(LineItem i) { return i.UnitPrice >= 25M; }
第二步:把花括號(hào){}替的換為L(zhǎng)ambda運(yùn)算符=>,變?yōu)?
(LineItem i) => return i.UnitPrice >= 25M;
第三步:去掉return和分號(hào),語(yǔ)句變成表達(dá)式
(LineItem i) => i.UnitPrice >= 25M
第四步:由于編譯器會(huì)自動(dòng)進(jìn)行類型推斷,所以我們還可以把LineItem去掉。
i => i.UnitPrice >= 25M
這樣就把匿名方法變成了Lambda表達(dá)式。
var anon = LineItemsList.Find( i = > i.UnitPrice > = 25M );
由此可見(jiàn)Lambda表達(dá)式是由Lambda運(yùn)算符分割開(kāi)的兩部份組成。右邊部分代表運(yùn)算的語(yǔ)句塊,左邊部分代表的是運(yùn)算需要的參數(shù)。

9.標(biāo)準(zhǔn)查詢操作(Standard Query Operators SQO)
標(biāo)準(zhǔn)查詢操作是對(duì)IEnumerable<T>接口追加的一系列的擴(kuò)展方法。通過(guò)這些擴(kuò)展方法對(duì)實(shí)現(xiàn)IEnumerable<T>接口的集合、數(shù)組進(jìn)行一系列的查詢操作。一些比較常用的擴(kuò)展方法有Where()/OrderBy()/Select()等,LinQ標(biāo)準(zhǔn)查詢操作我們將在后面詳細(xì)闡述。
LinQ中的from關(guān)鍵字并不是擴(kuò)展方法,因此它不是SQO。from只是為in關(guān)鍵字后的序列指定一個(gè)別名。
C#3.0的查詢表達(dá)式是以一個(gè)或多個(gè)“from 別名 in 序列名”子句開(kāi)始,以select或group子句結(jié)束。而join/let/where/orderby等子句是可選的,需要寫在from和select/group子句中間。

下面是對(duì)內(nèi)存中List<productList>集合進(jìn)行查詢的例子
var noStock = from p in productList
              where p.UnitsInStock == 0
              orderby p.Category, p.ProductID
              select new { p.ProductID, p.Category, p.ProductName };
編譯器會(huì)自動(dòng)把上面的表達(dá)式語(yǔ)句翻譯成下面的鏈?zhǔn)椒椒ㄕ{(diào)用,在鏈?zhǔn)椒椒ㄕ{(diào)用中使用的就是lambda表達(dá)式
var noStock = productList
    .Where(p = > p.UnitsInStock == 0)
    .OrderBy(p = > p.Category)
    .ThenBy(p = > p.ProductID)
    .Select(p = > new { p.ProductID, p.Category, p.ProductName });

10.IQueryable<T>接口
IQueryable<T>類型不是集合,他們是支持多態(tài)、優(yōu)化、動(dòng)態(tài)查詢功能的LinQ查詢序列,它能夠把標(biāo)準(zhǔn)化查詢操作(SQO)轉(zhuǎn)換成表達(dá)式樹(shù)。簡(jiǎn)而言之,IQueryable<T>接收的對(duì)象不是集合,而是查詢表達(dá)式樹(shù)。
我們可以使用IQueryable<T>的ToList()方法來(lái)把查詢序列變成List<T>類型,使用ToArray()方法把查詢序列變成數(shù)組類型。
IEnumerable<T>接口中有個(gè)AsQueryable()方法,該方法返回的是也IQueryable<T>類型。

(原創(chuàng):灰灰蟲(chóng)的家http://hi.baidu.com/grayworm)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多