2010-03-29 6 views
6

Esiste comunque la possibilità di refactoring di questo codice? L'unica differenza è l'ordine per parte.La query LINQ deve essere crescente o decrescente nella stessa query

Idealmente mi piacerebbe usare un'espressione delegato/lambda in modo che il codice è riutilizzabile, ma non so come aggiungere condizionalmente e rimuovere l'OrderBy operatori di query e OrderByDescending

var linq = new NorthwindDataContext(); 

     var query1 = linq.Customers 
      .Where(c => c.ContactName.StartsWith("a")) 
      .SelectMany(cus=>cus.Orders) 
      .OrderBy(ord => ord.OrderDate) 
      .Select(ord => ord.CustomerID); 

     var query2 = linq.Customers 
      .Where(c => c.ContactName.StartsWith("a")) 
      .SelectMany(cus => cus.Orders) 
      .OrderByDescending(ord => ord.OrderDate) 
      .Select(ord => ord.CustomerID); 

risposta

12

È possibile creare il proprio metodo di estensione riutilizzabile che farà questo:

public static IOrderedQueryable<TSource> OrderBy<TSource, TKey> 
    (this IQueryable<TSource> source, 
    Expression<Func<TSource, TKey>> keySelector, 
    bool ascending) 
{ 
    return ascending ? source.OrderBy(keySelector) 
      : source.OrderByDescending(keySelector); 
} 

e analogamente per ThenBy:

public static IOrderedQueryable<TSource> ThenBy<TSource, TKey> 
    (this IOrderedQueryable<TSource> source, 
    Expression<Func<TSource, TKey>> keySelector, 
    bool ascending) 
{ 
    return ascending ? source.ThenBy(keySelector) 
      : source.ThenByDescending(keySelector); 
} 
+0

Cool. Grazie Jon. –

+0

Un po 'fuori tema, ma quanto sopra verrà tradotto correttamente in Linq2SQL? IOW è abbastanza intelligente da vedere un metodo 'non supportato' ed eseguirlo prima che costruisca un albero di sintassi e generi l'SQL? Mi stavo solo chiedendo, mai provato. :) – leppie

+1

@leppie: chiama semplicemente i metodi Queryable esistenti, ovvero quelli che creano l'albero delle espressioni. Nota che * non * funzionerà contro 'IEnumerable ' al momento, sebbene tu possa facilmente scrivere metodi di estensione equivalenti che farebbero. –

0

con i numeri, ecc normalmente puoi semplicemente annullare la 'variabile di ordinamento'.

Con DateTime, non ne sono così sicuro. Potresti provare a utilizzare Timespan.

2

È possibile suddividere la query in bit e utilizzare la logica del flusso di controllo. LINQ to SQL creerà magicamente la query corretta come se avessi digitato tutto su una riga! Il motivo per cui questo funziona è che la query non viene inviata al database finché non si richiedono i dati, ma viene invece memorizzata come espressione.

var linq = new NorthwindDataContext(); 
var query = linq.Customers 
    .Where(c => c.ContactName.StartsWith("a")) 
    .SelectMany(cus=>cus.Orders); 

IOrderedQueryable<Order> query2; 
if (useAscending) { 
    query2 = query.OrderBy(ord => ord.OrderDate); 
} else { 
    query2 = query.OrderByDescending(ord => ord.OrderDate); 
} 

var query3 = query2.Select(ord => ord.CustomerID); 
+0

Errorrr !!!!!!!!! Il tuo ordine deve accadere prima di selezionare, altrimenti hai a che fare con un diverso tipo :) – leppie

+0

Grazie Marco. Importa se l'ordine degli operatori di query viene inserito dopo select()? –

+0

@leppie: Sì, mi spiace di non averlo notato! –

0

bene, se si dispone di una condizione in cui si decide se l'ordine da è crescente o decrescente è possibile utilizzare questo

var query1 = linq.Customers 
.Where(c => c.ContactName.StartsWith("a")) 
.SelectMany(cus=>cus.Orders) 

if(SortAscending) 
    query1 = query1.OrderBy(ord => ord.OrderDate); 
else 
    query1 = query1.OrderByDescending(ord => ord.OrderDate); 

var query2 = query1.Select(ord => ord.CustomerID); 
+0

Vedi, hai fatto lo stesso errore della risposta qui sotto (ora è corretto). – leppie

+0

@leppie: non solo è stato corretto, ma è al di sopra ora, non al di sotto. Quindi il tuo commento è impreciso e probabilmente più confuso che utile! Perché non ripetere il tuo commento piuttosto che provare a utilizzare un riferimento? In altre parole, scrivi questo: "Il tuo ordine deve accadere prima di selezionare, altrimenti hai a che fare con un tipo diverso". ;-) –

+0

Lì, risolto. Comunque penso di preferire la risposta di jon anche a me stesso ;-) –

1
return from T in bk.anbarsabts 
     where T.kalaname == str 
     orderby T.date descending 
     select new { T.date, T.kalaname, T.model, T.tedad };