2015-07-22 42 views
0

編輯:試圖讓我的問題更清楚一點。如何在運行時動態組合一組LINQ查詢?

我試圖構建一個LINQ表達式,它是幾個LINQ語句的交集。現在,我可以手動將兩個語句交叉在一起,並得到期望的結果。

 var results = 
       context.UserBooleanAttributes.Where(x => x.UserAttributeID == 1 && x.Value).Select(a => a.User) 
      .Intersect(
       context.UserBooleanAttributes.Where(y => y.UserAttributeID == 2 && y.Value).Select(b => b.User) 
      ); 

     Assert.Equal(100,results.Count()); 

我的目標是動態構建它,例如使用for-loop。由於我使用的是LINQ,我想推遲執行,直到我實際調用某些強制執行的結果

回答

1

你的代碼進行重構,以獲得用戶的多個列表:

IEnumerable<IEnumerable<User>> GetListOfListsOfUsers(int xTimes) 
{ 
    for (int i = 1; i <= xTimes; i++) 
    { 
     var someUsers = context.UserBooleanAttributes 
           .Where(x => x.UserAttributeID == i && x.Value == true) 
           .Select(a => a.User); 
     yield return someUsers; 
    } 
} 

var listOfListsOfUsers = GetListOfListsOfUsers(xTimes); 

現在的問題變成intersection of multiple lists

var intersection = listOfListsOfUsers.Aggregate((previousList, nextList) => previousList.Intersect(nextList));        
1

看起來你只是想的User列表:

var list = new List<User>(); 

然後你就可以添加每組結果的,因爲你讓他們:

list.AddRange(someUsers); 

如果User是一個類,你可以執行Intersect,並且您只需要不同的值(在您的代碼中似乎是這種情況),請考慮一次完成,並在末尾調用Distinct()

var attrIDs = Enumerable.Range(1, xTimes); 

list.AddRange(context.UserBooleanAttributes 
        .Where(x => attrIDs.Contains(x.UserAttributeID) && x.Value) 
        .Select(a => a.User) 
        .Distinct()); 
+0

用的AddRange的問題是,它似乎引起表達式被評估。我在OP中沒有提到的是,我將這與EntityFramework結合使用,並且在使用Intersect構建我的列表後,我希望能夠檢查list.ToString()以查看基礎SQL代碼。 – WhiskerBiscuit

+0

@WhiskerBiscuit哦,好吧,這是有道理的,你想推遲執行。我最後的片段呢?您可以嘗試將查詢拉出,放入單獨的變量中,並在其上放置一個斷點。除非你真的只是想看看'Intersect'語句看起來像什麼...... –

+0

更新了我的問題。 AddRange的問題在於,它也迫使立即執行該語句。 – WhiskerBiscuit

0

這裏遇到了一些問題。首先是我需要一種方法來聲明我的匿名變量在循環之外使用。我通過使用IQueryable allBooleansTrue。我給它分配一個非空值來讓Resharper停止嘮叨我。第二個問題是我遇到了着名的closures issue。我解決了這個使用INT副本=我

 IQueryable<User> allBooleansTrue = new List<User>().AsQueryable(); 
     for (int i = 1; i <= numBools; i++) 
     { 
      int copy = i; //workaround to prevent closures using reference 
      var q = context.UserBooleanAttributes.Where(y => y.UserAttributeID == copy && y.Value) 
       .Select(a => a.User); 
      if (i == 1) 
       allBooleansTrue = q; 
      else 
       allBooleansTrue = allBooleansTrue.Intersect(q); 

第一次迭代取代我的外層變量(allBooleansTrue)與LINQ聲明的內容。其他迭代執行交集。這裏有一點點黑客,但這似乎有效(到目前爲止)。我想我應該使用表情樹,但那是另一天。

對不起,我改變了我的代碼,爲原來的帖子,但我累死了,並從我的測試類複製。