2012-09-14 14 views
16

sto imparando su LINQ to SQL e tutto andava bene fino a quando qualcosa di strano è accaduto:DISTINCT() e OrderBy problema

Ho provato a fare un esempio di distinct, quindi, utilizzando il dabatase Northwind ho scritto la seguente query:

var query = 
    from o in db.Orders 
    orderby o.CustomerID 
    select new 
    { 
     o.CustomerID 
    }; 

se stampo il codice SQL generato da LINQ to SQL per la query memorizzata in query sembra che questo:

SELECT [t0].[CustomerID] 
FROM [dbo].[Orders] AS [t0] 
ORDER BY [t0].[CustomerID] 

Quindi, come al solito, la query porta tutti gli CustomerID per ogni Order nella tabella Orders ordinata alfabeticamente.

Ma! Se uso il metodo Distinct() in questo modo:

var query = (
    from o in db.Orders 
    orderby o.CustomerID 
    select new 
    { 
     o.CustomerID 
    }).Distinct(); 

La query porta i risultati attesi della clausola Distinct, ma i CustomerID s non sono ordinate, nonostante ho scritto orderby o.CustomerID!

La query SQL per questa seconda query LINQ è il seguente:

SELECT DISTINCT [t0].[CustomerID] 
FROM [dbo].[Orders] AS [t0] 

Come possiamo vedere ** clausola ORDER BY è mancante. Perché?

Perché la clausola ORDER BY scompare quando utilizzo il metodo Distinct()?

+1

Per inciso sintassi lambda è molto più semplice per le query di questo tipo: 'var query = db.Orders.Select (o => o .CustomerId) .Distinct(); ' – asawyer

risposta

28

Dal Queryable.Distinct documentation;

Il comportamento previsto è che restituisce una sequenza non ordinata degli elementi univoci nella fonte.

In altre parole, qualsiasi ordine di IQueryable esistente viene perso quando si utilizza Distinct() su di esso.

Quello che vuoi è probabilmente qualcosa di più simile a questo, un OrderBy() dopo il Distinct() è terminato;

var query = (from o in db.Orders 
      select new 
      { 
       o.CustomerID 
      }).Distinct().OrderBy(x => x.CustomerID); 
8

Provare a riordinare i membri per posizionare l'ordine dopo Distinto. Dovrete tornare al metodo di concatenamento:

db.Orders.Select(o=>o.CustomerId).Distinct().OrderBy(id=>id); 

Questo sarebbe il modo più efficace per impostare la query in LINQ Enumerable comunque, perché l'OrderBy sarebbe poi operare solo sulle oggetti unici e non su tutti loro. Inoltre, in base a MSDN, Enumerable.Distinct non garantisce comunque l'ordine di reso degli elementi, pertanto l'ordine prima della deduplicazione è inutile.

+3

No design. – asawyer

+0

... Sì, lo è: http://msdn.microsoft.com/en-us/library/system.linq.enumerable.distinct.aspx. La domanda è: perché Distinct non mantiene l'ordine degli elementi di input, quando così facilmente potrebbe semplicemente restituire il rendimento? – KeithS

+2

@KeithS Hai letto il tuo link ... "La sequenza dei risultati non è ordinata." Non è un bug quando è integrato nel design. –

3

A causa dell'uso di distinto, l'ordine dell'elenco restituito non è garantito. LinqToSql è abbastanza intelligente da riconoscerlo, quindi lo ignora.

Se effettui l'ordine DOPO il tuo Distinto, tutto avverrà come desideri.

var query = (from o in db.Orders 
      select new 
      { 
       o.CustomerID 
      }).Distinct().OrderBy(o => o.CustomerID); 

o

var query = db.Orders.Select(o => o.CustomerID).Distinct().OrderBy(o => o.CustomerID); 

Si prega di consultare questo articolo per chiarimenti:

http://programminglinq.com/blogs/marcorusso/archive/2008/07/20/use-of-distinct-and-orderby-in-linq.aspx

1

È possibile simulare OrdinaPer e distinto con questo counstruction:

var distinctItems = employees.GroupBy(x => x.EmpID).OrderBy(x => x).Select(y => y.First());