2013-01-09 148 views
1

已經有一種方法返回IEnumerable<User>,我一直在使用Linq/Entity Framework/SQL Server來返回結果。Linq complex - 枚舉性能

我(剛返回數據到客戶端之前在LINQ語句,鏈的末端)穿過一個艱難的條件scenario,這是更容易在C#迭代解決了Web服務器上就來了:

public IEnumerable<User> ReturnUsersNotInRoles() 
{ 
    IQueryable<User> z = (from users 
        //...many joins..conditions... 
        ).Distinct().Include(x => x.RoleUserLinks).ToList() 


    IEnumerable<User> list = new List<User>(); 

    foreach (User user in z) 
    { 
     bool shouldReturnUser = true; 

     foreach (var rul in user.RoleUserLinks) 
     { 
      if (rul.LinkStatusID == (byte)Enums.LinkStatus.Added) 
       shouldReturnUser = false; 
     } 
     if (shouldReturnUser) 
      list.Add(user); 
    } 

    return list; 
} 

問題:在C#中是否有更高性能/更少的內存開銷方式?

我只是從Linq中取回我需要的實體。沒有N+1的情況。性能目前非常好。

我意識到理想情況下我會在SQL/Linq中寫這個,因爲那時SQL Server會發揮它的魔力並快速爲我提供數據。不過,我正在用一個可能的v.hard查詢來平衡這個問題,以便理解,以及目前迭代的出色性能,以及對C#方式的理解。

回答

2

如何:

public IEnumerable<User> ReturnUsersNotInRoles() 
{ 
    var z = (from users 
        //...many joins..conditions... 
        ).Distinct().Include(x => x.RoleUserLinks); 

    var addedLinkStatusID = (int)Enums.LinkStatus.Added; 
    return z.Where(user => 
       false == user.RoleUserLinks.Any(link => link.LinkStatusID == addedLinkStatusID)) 
      .ToList(); 
} 

這應作爲一個SQL查詢完全運行 - 你可以做的第一部分(z)通過定義它的行的末尾添加.ToList()兌現。


順便說一句,關於你的問題,「在C#是有一個更好的性能/更少的內存開銷,這樣做的呢?」 - 好吧,首先您可以在設置shouldReturnUser = false;之後立即添加break聲明。

其次,我更喜歡使用LINQ元儘可能與否,我使用數據庫:

  1. 在正確使用時,使用LINQ方法的實施可能會以最快的速度或比任何你能更快寫。
  2. 更重要的是,它們通過有狀態的,容易出錯的編程來促進功能性,無狀態的編程。
  3. 另外,如果您的與數據庫一起工作,您可以決定是否要代碼作爲SQL查詢運行 - 您所要做的就是決定在哪裏實現。
+0

謝謝sinelaw。同意你的觀點。特別感謝在linq上看到如何做到這一點 - 能夠簡單地以功能性的方式表達它真是太棒了! –

0

您的循環相當於下面的LINQ查詢 - 我發現它比循環更容易理解,它允許在與查詢的第一部分結合時在服務器上完成執行。

var linkStatusAdded = (Byte)Enums.LinkStatus.Added; 

return z.Where(user => user.RoleUserLinks 
          .All(rul => rul.LinkStatusID != linkStatusAdded)) 
     .ToList(); 
+0

謝謝丹尼爾 - 感激。 –