2013-01-15 10 views
9

Mi riferisco a questo esempio: Return selected specified columnsSelezione di colonne specifiche tramite linq: cosa viene trasferito?

Citazione: Se BlobDetails non è l'entità LINQ, allora si può farlo direttamente:

var qry = from b in dc.Blobs 
      orderby b.RowVersion descending 
      select new BlobDetails { 
       Id = b.Id, Size = b.Size, 
       Signature = b.Signature, RowVersion = b.RowVersion}; 

return qry.ToList(); 

vedo che stanno selezionando specifica colonna in una query attraverso lo strumento ORM LINQ TO SQL. I critici degli strumenti ORM dicono che, se non ricordo male, gli strumenti ORM selezionano e restituiscono interi oggetti dalla tabella e limitano le opzioni di selezione solo di colonne specifiche, come si può fare con la classica programmazione SQL. Naturalmente, ho dei dubbi a riguardo quando vedo questo esempio, ma ciononostante continuo a pormi la domanda: il database restituisce solo le colonne selezionate, oppure restituisce l'intero oggetto, lasciando il filtro della colonna al ORM-tool?

Da questo esempio, hanno anche una classe chiamata Blobdetails:

public class BlobDetails 
{ 
    public int Id { get; set; } 
    public string Signature { get; set; } 
    public int Size { get; set; } 
    public System.Data.Linq.Binary RowVersion { get; set; }  
} 

Devo creare le mie classi ogni volta solo io desidero selezionare alcune colonne di una tabella tramite LINQ?

+2

solo passo con il debugger dopo la creazione qry oggetto e si può vedere che cosa query SQL è in realtà generato ;-) o provare LINQPad. – mipe34

risposta

12

Non è necessario creare nuove classi per selezionare poche colonne da una tabella. Puoi usare tipi anonimi per questo.

var qry = from b in dc.Blobs 
      orderby b.RowVersion descending 
      select new { b.Id, b.Size, b.Signature, b.RowVersion}; 

return qry.ToList(); 

Vengono trasferite solo le colonne selezionate. Non c'è differenza tra l'utilizzo di SQL semplice e l'utilizzo di LINQ in SQL. Quando si esegue la query LINQ, viene convertito in SQL semplice ed eseguito. Quindi il risultato è mappato ai tuoi oggetti.

È possibile utilizzare SQL Server Profiler per vedere quale query è stata generata ed eseguita sul server. Inoltre è possibile utilizzare LINQPad per vedere quale SQL verrà generato dalla query. Nel caso la vostra richiesta sarà lo stesso o si utilizza BlobDetails o oggetto anonimo:

SELECT [t0].[Id], [t0].[Size], [t0].[Signature], [t0].[RowVersion] 
FROM [Blobs] AS [t0] 
ORDER BY [t0].[RowVersion] DESC 
+0

C'è anche la molto utile proprietà 'DataContext # Log', che può essere impostata su qualsiasi' TextWriter' (come [questo qui] (http://stackoverflow.com/a/4234085/157247)) e ti mostra cosa sta facendo Linq-to-sql. –

1

Non è necessario creare classi personalizzate, è possibile restituire un tipo anonimo. È possibile scrivere qualcosa di simile

var qry = from b in dc.Blobs 
      orderby b.RowVersion descending 
      select new { 
       Id = b.Id, Size = b.Size, 
       Signature = b.Signature, RowVersion = b.RowVersion}; 

return qry.ToList(); 

Anche se la firma del metodo dovrebbe cercare di qualcosa di simile

public IEnumerable<object> GetItems() 

o

public dynamic GetItems() 

Quindi, se avete intenzione di utilizzare il risultato di query linq in ambito esterno come suggerito dall'esempio, si consiglia vivamente di creare le proprie classi.

+0

Sono curioso, quale sarà il tipo di ritorno di tale metodo ... – mipe34

+0

Il tipo di reso è un tipo anonimo, controlla questo link che ti spiegherà in dettaglio che tipo anonimo è: http://msdn.microsoft. it/it/us/library/bb397696.aspx –

+0

So cos'è un tipo anonimo. Nel tuo esempio il tipo di ritorno dovrà essere un Enumerable di oggetti. Volevo solo sottolineare che non è molto utile restituire un numero infinito di oggetti di cui non si conosce nulla. Quindi alla domanda dell'OP: dovresti usare la propria classe se vuoi usare quegli oggetti in qualche ambito esterno. – mipe34

2

Penso che la risposta alla tua prima domanda sia già nel POST che hai menzionato. Tuttavia ...

Se il numero BlobDetails non è entità LINQ, è sufficiente utilizzarlo nell'istruzione select per definire (ridurre) gli attributi di proiezione. Per esempio:

var qry = from b in dc.Blobs 
      select new BlobDetails { Id = b.Id, Size = b.Size } 

sarebbe compilare in query SQL come SELECT Id, Size FROM Blob ....

Ma se BlobDetails è LINQ entità che si avrà bisogno di utilizzare tale AsEnumerable() hack altrimenti si otterrà NotSupportedException: Explicit construction of entity type in query is not allowed.

var qry = from b in dc.Blobs.AsEnumerable() 
      select new BlobDetails { Id = b.Id, Size = b.Size } 

Modifica

Come @ Chris Pitman ha affermato nel suo commento questo approccio AsEnumerable() potrebbe creare gravi collo di bottiglia, beacause l'intera tabella sarebbe caricato in memoria prima di applicare la proiezione. Quindi non è raccomandato!

alla tua seconda domanda:

Sarà necessario creare classe personalizzata per gli oggetti che si desidera utilizzare con facilità al di fuori del campo di applicazione del metodo. Le proprietà di un oggetto anonimo sono visibili solo nell'ambito, dove sono state dichiarate e gli oggetti anonimi possono essere trasmessi solo per digitare object.

Quindi, se si desidera restituire oggetti anonimi dal metodo, il tipo restituito deve essere una enumerazione di object o dynamic come @xeondev indicato nel suo commento.

+1

Suggerirei di non eseguire mai il secondo modulo, poiché * * estrae interi record anche se non necessari. Inoltre, sarebbe troppo facile per qualcuno che non capisce di tirare indietro un intero tavolo. –

+0

Sì, sono d'accordo. Aggiornerò la mia risposta – mipe34

2

quando si fanno proiezioni LINQ in effetti seleziona solo quelle colonne e non c'è nulla che impedisca di materializzarlo come si desidera. Quindi nel tuo codice di esempio

select new BlobDetails 
{ 
    Id = b.Id, 
    Size = b.Size, 
    Signature = b.Signature, 
    RowVersion = b.RowVersion 
}; 

Solo b.id, B.Size, b.signature, & b.rowversion vengono selezionati. Puoi verificarlo con sql profiler o il tuo debugger, mi sembra di ricordare che esiste anche una funzione che puoi chiamare sul datacontext per ottenere l'ultima query che è stata eseguita.

+0

Questa è la risposta più diretta alla vera domanda. Essere in grado di limitare le query a un sottoinsieme di campi è una delle caratteristiche che distingue L2S e EF rispetto ad altri ORM. Rende molto più semplice la scrittura di routine di query performante! –

+0

(Plug Shameless) Controlla saucedb (http: //sauce.codeplex.com) Se ti piacciono L2S ed EF, ti potrebbe piacere molto il set di funzioni che offre. Permette le query in stile LINQ mentre aggiunge alcune altre caratteristiche. Dichiarazione di non responsabilità: l'ho scritto – iamkrillin

Problemi correlati