Condividi tramite


Query di oggetto (Entity Framework)

La classe generica ObjectQuery rappresenta una query che può restituire una raccolta di zero o più oggetti tipizzati. Un oggetto ObjectQuery appartiene a un oggetto ObjectContext che contiene le informazioni sulla connessione e sui metadati necessarie per creare ed eseguire la query. È possibile costruire un oggetto ObjectQuery con un operatore new e passare una stringa di query e il contesto dell'oggetto al costruttore. Tuttavia, in uno scenario più comune vengono utilizzate proprietà in una classe derivata ObjectContext per ottenere un'istanza dell'oggetto ObjectQuery che rappresenta una raccolta di set di entità. In genere, l'oggetto ObjectContext è sottoclassato, da una classe generata dagli strumenti di Entity Framework o dalle classi POCO, e mediante le proprietà nel contesto dell'oggetto vengono restituiti set di entità come oggetto ObjectQuery (in .NET Framework versione 3.5 SP1) o come ObjectSet (in .NET Framework versione 4). La classe ObjectSet consente di estendere la classe ObjectQuery per fornire funzionalità, ad esempio l'aggiunta ed eliminazione di oggetti, nel contesto di un set di entità tipizzato.

L'oggetto ObjectQuery predefinito fornisce una query iniziale che restituisce tutte le entità del tipo specificato. Questa query può essere ridefinita ulteriormente tramite LINQ to Entities o metodi del generatore di query.

Nell'esempio riportato di seguito viene eseguita la query sul contesto dell'oggetto per la raccolta di Products.

Using context As New AdventureWorksEntities
    Dim products As ObjectSet(Of Product) = context.Products

    Dim productsQuery = _
        From product In products _
        Select product

    Console.WriteLine("Product Names:")
    For Each product In productsQuery
        Console.WriteLine(product.Name)
    Next
End Using
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    IQueryable<Product> productsQuery = from product in context.Products
                                        select product;

    Console.WriteLine("Product Names:");
    foreach (var prod in productsQuery)
    {
        Console.WriteLine(prod.Name);
    }
}

Esecuzione di query

Una query di oggetto viene eseguita quando:

Si noti che, se come risultato dell'esecuzione di una query, non è stato restituito alcun valore dall'origine dati, i risultati conterranno una raccolta vuota e non un valore null.

Le query eseguite in Entity Framework vengono valutate in base ai dati contenuti nell'origine dati e i risultati non rifletteranno gli oggetti nuovi nel contesto dell'oggetto. Se un'entità con un'identità identica a quella sottoposta a query è già connessa al contesto, i dati dell'origine dati e quelli già presenti nel contesto vengono uniti in base all'oggetto MergeOption della query. Per ottenere i dati contenuti nella cache, utilizzare il metodo GetObjectStateEntries sulla classe ObjectStateManager. ObjectStateManager gestisce lo stato degli oggetti inclusi nel contesto di un oggetto, pertanto se si desidera ottenere tutti gli oggetti aggiunti, modificati e invariati, è possibile passare un operatore OR bit per bit dei valori EntityState seguenti al metodo GetObjectStateEntries: Added, Modified, Unchanged. Per ulteriori informazioni, vedere il blog in cui viene descritto come eseguire query locali.

Nell'esempio seguente viene chiamato il metodo Execute per l'esecuzione di una query:

Using context As New AdventureWorksEntities()
    Dim query As ObjectSet(Of Product) = context.Products

    ' Execute the query and get the ObjectResult. 
    Dim queryResult As ObjectResult(Of Product) = query.Execute(MergeOption.AppendOnly)
    ' Iterate through the collection of Product items. 
    For Each result As Product In queryResult
        Console.WriteLine("{0}", result.Name)
    Next
End Using
using (AdventureWorksEntities context =
    new AdventureWorksEntities())
{
    ObjectSet<Product> query = context.Products;

    // Execute the query and get the ObjectResult.
    ObjectResult<Product> queryResult = query.Execute(MergeOption.AppendOnly);
    // Iterate through the collection of Product items.
    foreach (Product result in queryResult)
        Console.WriteLine("{0}", result.Name);
}

Proiezione di query

Le query di oggetto spesso sono utilizzate per restituire dati del modello concettuale come oggetti entità, ma è possibile che restituiscano anche un oggetto DbDataRecord per risultati nidificati e proiezioni anonime o possono restituire tipi CLR primitivi per set di singoli valori.

LINQ to Entities e Entity SQL supportano entrambi la proiezione di query. Le considerazioni seguenti riguardano le proiezioni di query:

  • Alcuni metodi di estensione richiedono come input una raccolta con diversi risultati. Se un oggetto ObjectQuery rappresenta una query che restituisce una raccolta con un singolo risultato scalare e viene chiamato uno di questi metodi di estensione, viene generata una ArgumentException, come nell'esempio che segue.

    ' Define a query projection that returns 
    ' a collection with a single scalar result.
    Dim scalarQuery As New ObjectQuery(Of Int32)("100", context)
    
    ' Calling an extension method that requires a collection 
    ' will result in an exception. 
    Dim hasValues As Boolean = scalarQuery.Any()
    
    // Define a query projection that returns 
    // a collection with a single scalar result.
    ObjectQuery<Int32> scalarQuery =
        new ObjectQuery<Int32>("100", context);
    
    // Calling an extension method that requires a collection
    // will result in an exception.
    bool hasValues = scalarQuery.Any();
    
  • Se un oggetto ObjectQuery può restituire un valore null quando viene proiettato in un tipo primitivo, è necessario utilizzare la versione del tipo che ammette i valori Null. Nella query seguente viene utilizzato un oggetto DateTime che ammette i valori Null perché la proprietà ShipDate dell'oggetto SalesOrderHeader potrebbe restituire un valore null.

    Dim shipDateQuery As ObjectQuery(Of Nullable(Of DateTime)) = _
        context.SalesOrderHeaders.Where("it.CustomerID = @contactId", _
            New ObjectParameter("contactId", contactId)).SelectValue(Of Nullable(Of DateTime))("it.ShipDate")
    
    ObjectQuery<Nullable<DateTime>> shipDateQuery =
        context.SalesOrderHeaders
        .Where("it.CustomerID = @contactId",
            new ObjectParameter("contactId", contactId))
        .SelectValue<Nullable<DateTime>>("it.ShipDate");
    

    Per ulteriori informazioni, vedere l'argomento relativo ai tipi che ammettono i valori Null nella Guida per programmatori Visual Basic o l'argomento Nullable Types (C# Programming Guide).

Visualizzazione di comandi di archiviazione

Quando si esegue una query su un modello concettuale, in Entity Framework le query LINQ to Entities e Entity SQL basate sul modello concettuale vengono trasformate in query equivalenti sull'origine dati. Entity Framework fornisce i metodi System.Data.Objects.ObjectQuery.ToTraceString e System.Data.EntityClient.EntityCommand.ToTraceString che consentono di visualizzare questi comandi di archiviazione per un oggetto in fase di esecuzione senza dovere eseguire una traccia nell'origine dati. Per ulteriori informazioni, vedere Procedura: visualizzare i comandi di archiviazione (Entity Framework).

Recupero di un oggetto tramite EntityKey

Se si conosce il valore della chiave di un'entità, è possibile recuperarla dall'origine dati senza creare ed eseguire in modo esplicito una query di oggetto. I metodi GetObjectByKey e TryGetObjectByKey su ObjectContext restituiscono un oggetto con EntityKey specificato nel contesto dell'oggetto. Quando si utilizza GetObjectByKey, è necessario gestire un'eccezione ObjectNotFoundException quando l'oggetto EntityKey fornito non corrisponde a un'entità esistente. Per ulteriori informazioni, vedere Procedura: restituire un oggetto specifico utilizzando la relativa chiave (Entity Framework).

Vedere anche

Concetti

Esecuzione di query su un modello concettuale (Entity Framework)
Utilizzo di ObjectSet (Entity Framework)
Query compilate (LINQ to Entities)