Condividi tramite


Query in LINQ to Entities

Una query è un'espressione che recupera dati da un'origine dati. Le query sono in genere espresse in un linguaggio di query specializzato, ad esempio SQL per i database relazionali e XQuery per XML. Gli sviluppatori hanno pertanto dovuto apprendere un nuovo linguaggio di query per ogni tipo di origine dati o formato di dati su cui eseguono query. LINQ (Language-Integrated Query) offre un modello più semplice e coerente per l'utilizzo di dati in diversi tipi di origini dati e formati di dati. In una query LINQ vengono sempre utilizzati oggetti di programmazione.

Un'operazione di query LINQ comporta tre azioni: il recupero di una o più origini dati, la creazione della query e l'esecuzione della query.

È possibile utilizzare LINQ per eseguire query su origini dati che implementano l'interfaccia generica IEnumerable o IQueryable. Le istanze della classe generica ObjectQuery, che implementa l'interfaccia generica IQueryable, fungono da origine dati per le query LINQ to Entities. La classe generica ObjectQuery rappresenta una query che restituisce un'istanza o un insieme di entità tipizzate. Lo sviluppatore costruisce un'istanza da ObjectContext, che è la classe primaria per l'interazione con Entity Data Model (EDM) come oggetti CLR.

Nella query è necessario specificare esattamente le informazioni che si desidera recuperare dall'origine dati. Una query può inoltre specificare il modo in cui ordinare, raggruppare e formattare le informazioni prima di restituirle. In LINQ una query viene archiviata in una variabile. Se la query restituisce una sequenza di valori, la variabile di query deve essere un tipo queryable. La variabile di query non esegue azioni né restituisce dati, ma viene utilizzata solo per archiviare le informazioni sulla query. Dopo aver creato una query, è necessario eseguirla per recuperare tutti i dati.

In una query che restituisce una sequenza di valori la variabile di query stessa non contiene mai i risultati della query, ma viene utilizzata solo per l'archiviazione dei comandi della query. L'esecuzione della query viene posticipata fino a quando non viene eseguita un'iterazione della variabile di query in un ciclo foreach o For Each. In base a questo approccio, noto come esecuzione posticipata, la query viene eseguita qualche tempo dopo essere stata costruita. È quindi possibile eseguire una query il numero di volte desiderato. Tale caratteristica è utile, ad esempio, quando si dispone di un database che viene aggiornato da altre applicazioni. Nell'applicazione è possibile creare una query per recuperare le informazioni più recenti ed eseguire ripetutamente la query per restituire ogni volta informazioni aggiornate.

A differenza delle query posticipate, che restituiscono una sequenza di valori, le query che restituiscono un valore singleton vengono eseguite immediatamente. Alcuni esempi di query singleton sono Count, Max, Average e First. Queste query vengono eseguite immediatamente perché i risultati restituiti sono necessari per calcolare il risultato singleton. È inoltre possibile utilizzare il metodo ToList o ToArray in una query per forzare l'esecuzione immediata di una query che non restituisce un valore singleton. Queste tecniche per forzare l'esecuzione immediata possono risultare utili quando si desidera memorizzare nella cache i risultati di una query. Per ulteriori informazioni sull'esecuzione immediata e posticipata di query, vedere Introduzione a LINQ.

Query

Per la composizione di query LINQ to Entities è possibile utilizzare due diverse sintassi: la sintassi delle espressioni di query e la sintassi delle query basate su metodo. La sintassi delle espressioni di query è una novità di C# 3.0 e Visual Basic 9.0 e consiste in un set di clausole scritte in una sintassi dichiarativa simile a Transact-SQL o a XQuery. Common Language Runtime (CLR) di .NET Framework, tuttavia, non è in grado di leggere la sintassi delle espressioni di query. In fase di compilazione le espressioni di query vengono pertanto convertite in chiamate al metodo in modo da poter essere utilizzate da CLR. Questi metodi sono noti come operatori di query standard. Gli sviluppatori possono scegliere di chiamare direttamente tali metodi utilizzando la relativa sintassi anziché la sintassi delle query. Per ulteriori informazioni, vedere Sintassi delle query e sintassi dei metodi (LINQ). Per ulteriori informazioni su come utilizzare gli operatori di query standard, vedere Guida generale per programmatori LINQ.

Sintassi delle espressioni di query

Le espressioni di query vengono scritte in una sintassi di query dichiarativa. Questa sintassi consente a uno sviluppatore di scrivere query in un linguaggio di alto livello formattato in modo simile a Transact-SQL. Tramite la sintassi delle espressioni di query è possibile eseguire anche complesse operazioni di filtro, ordinamento e raggruppamento sulle origini dati utilizzando una quantità minima di codice. Per ulteriori informazioni, vedere Espressioni query LINQ (Guida per programmatori C#) e Operazioni di query di base (Visual Basic).

Nell'esempio seguente viene utilizzato Select per restituire tutte le righe di Product e visualizzare i nomi di prodotto.

Using AWEntities As New AdventureWorksEntities
    Dim products As ObjectQuery(Of Product) = AWEntities.Product

    Dim productNames = _
       From p In products _
       Select p.Name

    Console.WriteLine("Product Names:")
    For Each productName In productNames
        Console.WriteLine(productName)
    Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
    ObjectQuery<Product> products = AWEntities.Product;

    IQueryable<string> productNames =
       from p in products
       select p.Name;

    Console.WriteLine("Product Names:");
    foreach (var productName in productNames)
    {
        Console.WriteLine(productName);
    }
}

Sintassi delle query basate su metodo

Per comporre query LINQ to Entities, è inoltre possibile utilizzare query basate su metodo. La sintassi delle query basate su metodo è costituita da una sequenza di chiamate dirette ai metodi dell'operatore LINQ, in cui come parametri vengono passate espressioni lambda. Per ulteriori informazioni, vedere Espressioni lambda (Guida per programmatori C#).

In questo esempio viene utilizzato Select per restituire tutte le righe di Product e visualizzare i nomi di prodotto.

Using AWEntities As New AdventureWorksEntities


    Dim productNames = AWEntities.Product.Select(Function(p) p.Name)


    Console.WriteLine("Product Names:")
    For Each productName In productNames
        Console.WriteLine(productName)
    Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
    ObjectQuery<Product> products = AWEntities.Product;

    IQueryable<string> productNames = products.Select(p => p.Name);


    Console.WriteLine("Product Names:");
    foreach (var productName in productNames)
    {
        Console.WriteLine(productName);
    }
}

Composizione di query

Come accennato in precedenza in questo argomento, la variabile di query viene utilizzata solo per archiviare i comandi della query quando questa viene progettata in modo da restituire una sequenza di valori. Se la query non contiene un metodo che causa l'esecuzione immediata, l'esecuzione effettiva della query viene posticipata fino a quando non si esegue un'iterazione della variabile di query in un ciclo foreach o For Each. L'esecuzione posticipata consente di combinare più query o di estendere una query. Una query estesa viene modificata in modo da includere nuove operazioni. Le modifiche vengono quindi applicate all'eventuale esecuzione. Nell'esempio seguente la prima query restituisce tutti i prodotti. La seconda query estende la prima utilizzando Where per restituire tutti i prodotti di taglia "L":

Using AWEntities As New AdventureWorksEntities()
    Dim products As ObjectQuery(Of Product) = AWEntities.Product

    Dim productsQuery = _
        From p In products _
        Select p

    Dim largeProducts = _
        productsQuery.Where(Function(p) p.Size = "L")

    Console.WriteLine("Products of size 'L':")
    For Each product In largeProducts
        Console.WriteLine(product.Name)
    Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{

    ObjectQuery<Product> products = AWEntities.Product;

    IQueryable<Product> productsQuery =
        from p in products
        select p;

    IQueryable<Product> largeProducts = productsQuery.Where(p => p.Size == "L");

    Console.WriteLine("Products of size 'L':");
    foreach (var product in largeProducts)
    {
        Console.WriteLine(product.Name);
    }
}

Dopo aver eseguito una query, per tutte le query successive vengono utilizzati gli operatori LINQ in memoria. Se si scorre una variabile di query utilizzando un'istruzione foreach o For Each o chiamando uno degli operatori di conversione LINQ, la query viene eseguita immediatamente. Gli operatori di conversione includono ToList, ToArray, ToLookup e ToDictionary.

Nell'esempio seguente la prima query restituisce tutti i prodotti. La seconda query estende la prima query dopo che è stata eseguita, per restituire i prodotti rossi.

Using AWEntities As New AdventureWorksEntities()
    Dim products As ObjectQuery(Of Product) = AWEntities.Product

    Dim productsQuery = _
        From p In products _
        Select p

    Console.WriteLine("The list of products:")
    For Each Product As Product In productsQuery
        Console.WriteLine(Product.Name)
    Next

    Dim redProducts = productsQuery _
        .Where(Function(p) p.Color = "Red") _
        .Select(Function(p) p)

    Console.WriteLine("")
    Console.WriteLine("The list of red products:")
    For Each redProduct As Product In redProducts
        Console.WriteLine(redProduct.Name)
    Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{

    ObjectQuery<Product> products = AWEntities.Product;

    IQueryable<Product> productsQuery =
        from p in products
        select p;

    Console.WriteLine("The list of products:");
    foreach (Product product in productsQuery)
    {
        Console.WriteLine(product.Name);
    }

    IQueryable<Product> redProducts = productsQuery
        .Where(p => p.Color == "Red")
        .Select(p => p);

    Console.WriteLine("");
    Console.WriteLine("The list of red products:");
    foreach (Product redProduct in redProducts)
    {
        Console.WriteLine(redProduct.Name);
    }

}

Vedere anche

Altre risorse

LINQ to Entities
Nozioni di base su LINQ in C#
Introduzione a LINQ in Visual Basic