2013-01-09 96 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

谢谢丹尼尔 - 感激。 –