2016-05-25 18 views
5

Dane:Zastosowanie List <Tuple <int, int>>, aby powrócić danych w Linq

List<int> myList; 

Gdybym chciał wrócić danych, gdzie ID zapis został zawarty w tym liście chciałbym po prostu zrobić:

var q = db.Table.Where(c=> myList.Contains(c.ID)); 

Jednak podając:

List<Tuple<int, int>> myList; 

Jak napisać kwerendę Linq, aby zwrócić rekordy, gdy oba warunki są spełnione? Z jednego punktu danych chciałbym napisać:

var q = db.Table.Where(c=> 
      c.ID == myList.Item1 
      && c.AnotherValue == myList.Item2); 

Jak przekonwertować powyższe stwierdzenie do pracy na List<Tuple<int, int>>?

Odpowiedz

6

A Tuple to struktura, której nie można przetłumaczyć na sql przez dostawcę Linq. Rozwiązaniem może być dokonanie przełącznik Linq do obiektów

var q = db.Table.AsEnumerable() 
       .Where(c=> myList.Any(tuple => c.ID == tuple.Item1 && 
              c.AnotherValue == tuple.Item2)); 

Ale zła rzeczą tego rozwiązania jest, że masz zamiar załadować wszystkie wiersze z tej tabeli filtrowania w pamięci.

Innym rozwiązaniem mogłoby być używając Linqkit:

var predicate = PredicateBuilder.False<Table>(); 

foreach (string t in myList) 
{ 
    predicate = predicate.Or(c =>c.ID == t.Item1 && c.AnotherValue == t.Item2)); 
} 

db.Table.AsExpandable().Where(predicate); 

znajdziesz więcej informacji na temat tego ostatniego rozwiązania w tym link

+0

Tak, ale dla wielu wartości? Jeśli mam listę 100 par, nie chcę uruchamiać zapytania na każdym z nich. –

+0

Dzięki, PredicateBuilder wydaje się tutaj dobrym rozwiązaniem! –

+0

Nie ma za co;) – octavioccl

1
var q = db.Table.AsEnumerable().Where(c => myList.Any(tuple => c.ID == tuple.Item1 && 
               c.AnotherValue == tuple.Item2)); 

Z Any można sprawdzić, czy istnieje co najmniej jeden element w myList meczów Twój stan.

Jednak jak zauważyło @octaviocci, nie można tego przetłumaczyć na język SQL, więc trzeba wcześniej zadzwonić pod numer AsEnumerable() i wykonać lokalne filtrowanie, które może nie być tym, czego potrzebujesz, jeśli istnieje wiele nieistotnych rekordów.

0

Oto przykładowy kod, który ilustruje jedno podejście:

DataTable dt = new DataTable("demo"); 
// hydrate your table here... 

List<Tuple<int, int>> matches = new List<Tuple<int, int>>(); 

Func<List<Tuple<int,int>>, DataRow, bool> RowMatches = (items, row) => { 

     var rowValue1 = (int)row["Id"]; 
     var rowValue2 = (int)row["SomeOtherValue"]; 

     return items.Any(item => item.Item1 == rowValue1 && item.Item2 == rowValue2); 
    }; 

var results = dt.Rows.Cast<DataRow>().Where(r => RowMatches(matches, r)); 
Console.WriteLine(results.Any()); 
0

Zobacz kod poniżej:

List<Tuple<int, int>> myList; 

var set = new HashSet(myList); 

var q = db.Table.AsEnumerable().Where(c=> set.Contains(new Tuple(c.ID, c.AnotherValue))); 

Należy zauważyć, że zestaw skrótu służy do optymalizacji wydajności wykonywania klauzuli Where dla dużych myList.

+0

Czy po prostu nie pasuje to do KAŻDEGO elementu zestawu1 z DOWOLNYM elementem zestawu2? –

0

Od Tuple nie może być stosowany w Linq to Entities, można spróbować coś takiego:

List<int> items1 = myList.Select(t => t.Item1).ToList(); 
List<int> items2 = myList.Select(t => t.Item2).ToList(); 

var q = db.Table.GroupBy(m => { m.ID, m.AnotherValue }) 
       .Where(g => items1.Contains(g.Key.ID) && 
          items2.Contains(g.Key.AnotherValue)) 
       .SelectMany(g => g);