2016-05-25 17 views
5

Data:Usa List <tuple <int, int>> per tornare dati in Linq

List<int> myList; 

Se volevo restituire i dati in cui l'ID del record era contenuta in questa lista vorrei semplicemente fare:

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

Tuttavia, dato:

List<Tuple<int, int>> myList; 

Come scrivere una query Linq per restituire i record in cui sono soddisfatte entrambe le condizioni? Con un punto di dati avrei scritto:

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

Come dovrei convertire il dichiarazione di cui sopra per lavorare su un List<Tuple<int, int>>?

risposta

6

A Tuple è una struttura che non può essere convertita in sql dal provider Linq. Una soluzione potrebbe essere fare un interruttore per LINQ to Objects

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

Ma la cosa brutta di questa soluzione è che si sta andando a caricare tutte le righe dalla tabella per filtrare in memoria.

Un'altra soluzione potrebbe essere utilizzando 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); 

Troverete maggiori informazioni su questa ultima soluzione in questo link

+0

Sì, ma per più valori? Se ho una lista di 100 coppie, non voglio eseguire una query su ciascuna di esse. –

+0

Grazie, PredicateBuilder sembra una buona opzione qui! –

+0

prego;) – octavioccl

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

Con Any è possibile controllare se c'è almeno un elemento in myList le partite la sua condizione.

Ma come ha sottolineato @octaviocci, questo non è traducibile in SQL, quindi è necessario chiamare lo AsEnumerable() prima e fare il filtro localmente, che potrebbe non essere quello che si vuole se ci sono molti record irrilevanti.

0

Ecco alcuni esempi di codice che illustra un approccio:

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

Vedere il codice sottostante:

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))); 

Nota che il set di hash viene utilizzato per ottimizzare le prestazioni dell'esecuzione della clausola Where per large myList.

+0

Non si tratta semplicemente di abbinare QUALSIASI elemento di set1 con QUALSIASI oggetto di set2? –

0

Dal Tuple non possono essere utilizzati in Linq to Entities, si può provare qualcosa di simile:

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); 
Problemi correlati