2009-04-28 100 views
12

下面是返回相同數據的兩個查詢。其他風格我不確定哪個更好。LINQ查詢表達式和擴展方法有什麼區別

什麼因素影響這些查詢? 使用其中一種風格有什麼好處?

樣品1個

var x = from s in db.Surveys 
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID 
    join q in db.Questions on sq.Question_ID equals q.ID 
    join qg in db.Question_Groups on q.ID equals qg.Question_ID 
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type) 
    select new { question = sq.Question, status = sq.Status, grp = qg }; 

樣品2

var x = db.Surveys.Where(s => s.Type_ID.Equals(typeID) & s.Type.Equals(type)) 
       .Join(db.Survey_Questions, 
         s => s.ID, 
         sq => sq.Survey_ID, 
         (s, sq) => new 
         { 
          question = sq.Question, 
          status = sq.Status 
         }) 
       .Join(db.Question_Groups, 
         q => q.question.ID, 
         qg => qg.Question_ID, 
         (q, qg) => new 
         { 
          question = q.question, 
          status = q.status, 
          group = qg 
         }).ToList(); 
+0

其值得一提的樣品是不相同...... – 2009-04-28 04:43:55

+0

另外,.ToList()結尾的力量相當不同的執行。第一個x是IQueryable類型,第二個是IList 。 – 2010-06-03 18:36:43

回答

19

更新:你有固定的標題,所以忽略了咆哮。

你的問題的標題無關,與你的代碼示例。你的問題意味着一種語法是IEnumerable,另一種是IQueryable,但這是不正確的。在您的樣品,如果db.Surveys是一個IQueryable,然後您的樣品使用IQueryable的。我會盡量回答這兩個問題都是

你的兩個代碼示例是編寫相同的LINQ查詢(假設他們是寫得很好),只是方式不同。示例1中的代碼只是示例2中代碼的簡寫。編譯器會以相同方式處理這兩個示例中的代碼。想想C#編譯器會如何處理int?Nullable<System.Int32>相同。 C#和VB.Net語言都提供了這種簡寫查詢語法。其他語言可能沒有這種語法,您將不得不使用示例2語法。事實上,其他語言甚至可能不支持擴展方法或lambda表達式,並且還需要使用更加醜陋的語法。


更新:

爲了進一步採取Sander的例子,當你寫這個(查詢理解語法):

var surveyNames = from s in db.Surveys select s.Name 

認爲編譯器開啓的是簡寫成這個(擴展方法和λ表達):

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name); 

但實際上擴展方法和lambda表達式本身就是簡寫。編譯器發出這樣的事情(不完全,但只給一個想法):

Expression<Func<Survey, string>> selector = delegate(Survey s) { return s.Name; }; 
IQueryable<string> surveryNames = Queryable.Select(db.Surveys, selector); 

注意Select()Queryable類只是一個靜態方法。如果您的.NET語言不支持查詢語法,lambdas或擴展方法,那麼您將不得不自己編寫代碼。


什麼是使用一種風格比其他的好處?

對於小的查詢,擴展方法可以更緊湊:

var items = source.Where(s => s > 5); 

此外,擴展方法的語法可以更靈活,例如條件where子句:

var items = source.Where(s => s > 5); 

if(smallerThanThen) 
    items = items.Where(s => s < 10); 
if(even) 
    items = items.Where(s => (s % 2) == 0); 

return items.OrderBy(s => s); 

另外,只有通過擴展方法語法(Count(),Aggregate(),Take(),Skip(),ToList(),ToArray()等)才能使用幾種方法,所以如果我使用其中的一種方法,通常會以這種語法編寫整個查詢以避免混合b其他語法。

var floridaCount = source.Count(s => s.State == "FL"); 

var items = source 
      .Where(s => s > 5) 
      .Skip(5) 
      .Take(3) 
      .ToList(); 

在另一方面,當查詢變得更大,更復雜,查詢綜合語法可以更清晰,特別是一旦你開始與一些letgroupjoin複雜等

在結束我通常會爲每個特定的查詢使用更好的作品。


更新:您固定您的標題,所以忽略休息...

現在,關於你的標題:關於LINQ,IEnumerable和IQueryable的非常相似。它們都有幾乎相同的擴展方法(Select,Where,Count等),主要的區別在於IEnumerable以Func<TIn,TOut>作爲參數,IQueryable以Expression<Func<TIn,TOut>>作爲參數。你用同樣的方式表達(通常是lamba表達式),但在內部它們完全不同。

IEnumerable是LINQ to Objects的入口。可以在任何IEnumerable(數組,列表,任何可以迭代的東西)上調用LINQ to Objects擴展方法,並且Func<TIn,TOut>在編譯時轉換爲IL,並在運行時像普通方法代碼一樣運行。請注意,其他一些LINQ提供程序使用IEnumerable,因此實際上在後臺使用LINQ to Objects(LINQ to XML,LINQ to DataSet)。

IQueryable的是使用LINQ到SQL,LINQ到需要檢查你的查詢,而是把它翻譯直接執行代碼的實體,和其他LINQ提供程序。在編譯時,IQueryable查詢及其Expression<Func<TIn,TOut>>不會編譯爲IL。而是創建一個表達式樹,並可以在運行時檢查。這允許將語句翻譯成其他查詢語言(例如T-SQL)。表達式樹可以在運行時編譯成Func < TIn,TOut >,並在需要時執行。

可以在this question中找到一個示例,其中OP想要在SQL Server中執行LINQ to SQL查詢的一部分,將對象轉換爲託管代碼,並將LINQ to query中的其餘查詢。爲了實現這一點,他所要做的就是將IQueryable投入到他希望切換髮生的IEnumerable中。

3

LINQ爲技術時髦詞語。

IQueryable的是用於通過一個LINQ .NET接口。

除了款式以外,兩者沒有區別。使用你喜歡的任何風格。

我更喜歡長的語句的第一個樣式(如一個如圖所示),第二個非常簡短的發言。

0

我覺得你的問題是更好的措辭這樣的,「這是什麼相對於LINQ的IEnumerable <牛逼>和IQueryable的<牛逼>之間的區別」

LINQ查詢默認返回一個IQueryable <牛逼>。 IQueryable <T>允許您在執行之前將其他過濾器或「子句」追加到查詢中。

你LINQ查詢(第一實例)和您的使用LINQ方法鏈接(第二實例)產生相同的結果,與不同的語法。

是可能的寫LINQ查詢作爲LINQ方法鏈,反之亦然。這真的取決於你的喜好。

@Lucas:不同的是IEnumerable的<Ť>確實內存查詢和IQueryable的<Ť>確實外的存儲器。也就是說,一旦你處於迭代器foreach中,就使用IEnumerable,並且在通過擴展方法或使用LINQ from o in object synatax構建查詢時,您正在構建一個IQueryable <T>。 IQueryable <T>只要觸摸枚舉器就會執行。

1

1.您的問題標題與您提出的問題不符。
2.你的問題標題沒有意義。 Linq代表語言集成查詢(Language Integrated Query),是一系列技術和實踐的總稱,IQueryable是一種常用於促進Linq的接口。你是比較蘋果和桔子
3 /關於您的實際問題,主要的區別是風格,對於這樣一個複雜的查詢,我個人的喜好是第二個版本,因爲它清楚地顯示了結果集的進展。

2

的,其中在第一個例子條款實際上是在你的第二個方法Where子句只是語法糖。事實上,你可以編寫自己的類,它與Linq或IQueryable無關,只要有一個Where方法,就可以使用該語法糖。例如:

public class MyClass 
    { 

     public MyClass Where<T>(Func<MyClass, T> predicate) 
     { 
      return new MyClass { StringProp = "Hello World" }; 
     } 

     public MyClass Select<T>(Func<MyClass, T> predicate) 
     { 
      return new MyClass(); 
     } 



     public string StringProp { get; set; } 
    } 

這顯然是一個愚蠢的例子,但要注意,有一個Where方法只返回與stringprop設置爲你好世界一個新的MyClass的。爲了演示:

MyClass a = new MyClass(); 
      var q = from p in a 
        where p.StringProp == "foo" // doesnt matter what we put here, as we're not really checking the predicate 
        select p; 
      Console.WriteLine(q.StringProp); 

這將導致寫出「Hello World」。再一次,這個例子顯然毫無意義,但它證明了「where」語法只是在你的代碼中尋找一個Func的Where方法。

2

查詢表達式和擴展方法有兩種方法可以做到同樣的事情。查詢表達式在編譯時會轉換爲擴展方法 - 它們只是對SQL更加適應的人們的語法糖。

當你這樣寫:

var surveyNames = from s in db.Surveys select s.Name; 

編譯器轉換成這樣:

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name); 

真的,我覺得都只是市場原因創建查詢表達式 - 類似於SQL的語言結構採取行動作爲LINQ開發時的引人注目者,並不能提供太多的實際用途。我發現大多數人只是直接使用擴展方法,因爲它們導致了更統一的編碼風格,而不是混合使用C#和SQL。

1

樣本1是的LINQ的頂級代表,它是更具可讀性,並在編譯它會轉化爲表達式樹即你樣品2

var x = from s in db.Surveys 
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID 
    join q in db.Questions on sq.Question_ID equals q.ID 
    join qg in db.Question_Groups on q.ID equals qg.Question_ID 
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type) 
    select new { question = sq.Question, status = sq.Status, grp = qg }; 

你可以試試下面的代碼來獲取表達書面查詢

var exp=x.Expression; 

表達式被用來當查詢不太複雜

0

還有一點值得一提的是,LINQ的擴展方法堅持以C#語言而查詢理解的東西是像編譯器內置的那樣進行預處理的。 即你可以瀏覽到。選擇的定義(X => ,而你不能from ... where ... select