Udostępnij za pośrednictwem


Object Queries

The ObjectQuery generic class represents a query that can return a collection of zero or more typed objects. An ObjectQuery belongs to an ObjectContext that contains the connection and metadata information that is necessary to compose and execute the query. You can construct an ObjectQuery with a new operator and pass a query string and the object context to the constructor. However, a more common scenario is to use properties on an ObjectContext derived class to get an ObjectQuery instance that represents a collection of entity sets. Typically, the ObjectContext is subclassed, either by a class generated by the Entity Framework tools or by your POCO classes, and the properties on the object context return entity sets as either an ObjectQuery (in .NET Framework version 3.5 SP1) or as an ObjectSet (in .NET Framework version 4). The ObjectSet class extends the ObjectQuery class to provide functionality, such as adding and deleting objects, in the context of a typed entity set.

The default ObjectQuery provides a starting query that returns all entities of the specified type. This query can be further refined by using LINQ to Entities or query builder methods.

The following example queries the object context for the collection of 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);
    }
}

Query Execution

An object query is executed when:

  • It is enumerated by a foreach (C#) or For Each (Visual Basic) statement.

  • It is enumerated by a collection operation such as ToArray, ToDictionary or ToList.

  • The Execute method is explicitly called.

  • LINQ operators such, as First or Any are specified in the outermost part of the query. For more information, see Query Builder Methods.

Note, if as a result of a query execution, nothing was returned from the data source, the results will contain an empty collection and not a null.

Queries executed by the Entity Framework are evaluated against the data in the data source and the results will not reflect against the new objects in the object context. If an entity with the same identity as the one being queried for is already attached to the context, the data coming from the data source and the data already in the context are merged according to the MergeOption of the query. To get the data that is in the cache, use the GetObjectStateEntries method on the ObjectStateManager class. The ObjectStateManager manages the state of objects inside an object context, so if you want to get all the objects that were added, modified and unchanged, you can pass a bitwise OR of the following EntityState values to the GetObjectStateEntries method: Added, ModifiedUnchanged. For more information see the blog that demonstrates how to perform local queries.

In the following example, the Execute method is called to execute a 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);
}

Query Projection

Object queries are often used to return conceptual model data as entity objects, but they may also return a DbDataRecord object for nested results and anonymous projections, or they can return primitive CLR types for sets of single values.

LINQ to Entities and Entity SQL both support query projection. The following considerations apply to query projections:

  • Some extension methods require collection of many results as input. If a ObjectQuery represents a query that returns a collection with a single scalar result, and one of these extension methods is called, an ArgumentException is thrown, as in the following example.

    ' 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();
    
  • If an ObjectQuery might return a null value when projected to a primitive type, you should use the nullable version of the type. The following query uses a nullable DateTime because the ShipDate property of the SalesOrderHeader object might return a null value.

    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");
    

    For more information, see Nullable Types (Visual Basic Programming Guide) or Nullable Types (C# Programming Guide).

Viewing Store Commands

When you query a conceptual model, the Entity Framework transforms the LINQ to Entities and Entity SQL query based on the conceptual model into an equivalent query against the data source. The Entity Framework provides the System.Data.Objects.ObjectQuery.ToTraceString and System.Data.EntityClient.EntityCommand.ToTraceString methods, which enable you to view these store commands at runtime without having to run a trace against the data source. For more information, see How to: View the Store Commands.

Retrieving an Object by Its EntityKey

If you know the key value of an entity, you can retrieve it from the data source without explicitly creating and executing an object query. The GetObjectByKey and TryGetObjectByKey methods on ObjectContext will return an object with the specified EntityKey into the object context. When you use GetObjectByKey, you must handle an ObjectNotFoundException when the provided EntityKey does not correspond to an existing entity. For more information, see How to: Return a Specific Object Using its Key.

See Also

Concepts

Querying a Conceptual Model
Working with ObjectSet
Compiled Queries (LINQ to Entities)