Data Access has been discontinued. Please refer to this page for more information.

Obtaining a Set of Objects by Using ObjectKey

The Data Access context (through the OpenAccessContextBase class) exposes the generic GetObjectsByKeys<T>() method that allows you to perform bulk select (retrieve a set of instances) from a given persistent entity through their ObjectKey identifications. The signature of the method is:

IGetObjectsByKeysResult<T> GetObjectsByKeys<T>(IEnumerable<ObjectKey> keys)

Where T is the persistent entity type, or object in artificial types scenario.

The IGetObjectsByKeysResult<T> interface exposes the following members:

public interface IGetObjectsByKeysResult<T> : IEnumerable<T>, IEnumerable
{
    bool HasMissing { get; }

    IEnumerable<ObjectKey> GetMissing();
}

The ObjectKey class and the IGetObjectsByKeysResult<T> interface reside in the Telerik.OpenAccess namespace.

This article will provide you with the following details:

  1. General Information and Behaviour of GetObjectsByKeys<T>()
  2. Query Entities with a Single Property Identity
  3. Query Entities with a Composite Identity
  4. Requirements to the Input Parameter

General Information and Behaviour of GetObjectsByKeys<T>()

Through the method, you can query for the instances of persistent entities with a single property identity or with a composite identity. The returned result implements the IEnumerable<T> interface, and the order of the objects in it will be the same as the one of the items in keys. If keys contains ObjectKey objects for which there are no records in the database, the HasMissing property exposed through the interface would be set to True. In this case, through the GetMissing() method, you can obtain an enumeration from the ObjectKey instances, for which GetObjectsByKeys<T>() did not retrieve data from the database. In the opposite scenario, when the method returned an object for each ObjectKey in keys, the value of this property would be False.

Once the method is executed, it will load the necessary data in-memory. Telerik Data Access will take care to create on demand instances of the T persistent type (from the retrieved data). Furthermore, the method will request the data only for those database records, which are not present in the cache of the current context instance and Second Level Cache. After all the necessary data are retrieved from the database, both the cache of the current context instance and Second Level Cache will be populated with it.

Additionally, Telerik Data Access will respect any fetch strategies applied on the context instance when it executes the method.

Query Entities with a Single Property Identity

The general workflow in this case requires you to have the identity values in-memory and to compose the collection of ObjectKey instances through them. For example:

using (FluentModel dbContext = new FluentModel())
{
    int[] ids = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 };

    IEnumerable<ObjectKey> keys = ids.Select(x =>
        new ObjectKey("NorthwindOA.Example.Category", x));

    IGetObjectsByKeysResult<Category> items = 
        dbContext.GetObjectsByKeys<Category>(keys);

    List<Category> categoryItems = items.ToList();
}
Using dbContext As New FluentModel()
    Dim ids() As Integer = { 1, 2, 3, 4, 5, 6, 7, 8 }

    Dim keys As IEnumerable(Of ObjectKey) = 
        ids.Select(Function(x) New ObjectKey("NorthwindOA.Example.Category", x))

    Dim items As IGetObjectsByKeysResult(Of Category) = 
        dbContext.GetObjectsByKeys(Of Category)(keys)

    Dim categoryItems As List(Of Category) = items.ToList()
End Using

How to obtain an ObjectKey instance for an object of a given persistent entity is demonstrated in the Obtaining an ObjectKey article.

In this case, the SQL statements generated and executed with the call to the method correspond to this pattern:

SELECT * 
FROM [Categories] 
WHERE ([CategoryID] 
IN (@p0,@p1,@p2,@p3,@p4,@p5,@p6,@p7))

A single call to the method may generate multiple statements of this kind, according to the specifics of the backend.

Query Entities with a Composite Identity

The general workflow in this case requires you to have the composite identity values in-memory and to build the collection of ObjectKey instances through them. The next example demonstrates the case when the identity consists of two properties:

using (FluentModel dbContext = new FluentModel())
{
    List<ObjectKey> odrderDetailId = new List<ObjectKey>()
    {
        new ObjectKey("NorthwindOA.Example.OrderDetail", 
                      new[] { new ObjectKeyMember("OrderID", 10250),
                              new ObjectKeyMember("ProductID", 41) }),
        new ObjectKey("NorthwindOA.Example.OrderDetail", 
                      new[] { new ObjectKeyMember("OrderID", 10251),
                              new ObjectKeyMember("ProductID", 22) }),
    };

    IGetObjectsByKeysResult<OrderDetail> items = 
        dbContext.GetObjectsByKeys<OrderDetail>(odrderDetailId);

    List<Category> categoryItems = items.ToList();
}
Using dbContext As New FluentModel()
    Dim odrderDetailId As New List(Of ObjectKey)() From 
    {
        New ObjectKey("NorthwindOA.Example.OrderDetail", 
                     { New ObjectKeyMember("OrderID", 10250), 
                       New ObjectKeyMember("ProductID", 41) }), 
        New ObjectKey("NorthwindOA.Example.OrderDetail", 
                     { New ObjectKeyMember("OrderID", 10251), 
                       New ObjectKeyMember("ProductID", 22) })
    }

    Dim items As IGetObjectsByKeysResult(Of OrderDetail) = 
        dbContext.GetObjectsByKeys(Of OrderDetail)(odrderDetailId)

    Dim categoryItems As List(Of Category) = items.ToList()
End Using

In this scenario, the GetObjectsByKeys<T>() method is not supported for VistaDB and Firebird. Telerik Data Access will throw an exception, if ObjectKey objects created for an entity with composite identity is passed to the method against these backends.

In this scenario Telerik Data Access will execute the method by generating a set of SQL statements following the pattern demonstrated below:

CREATE TABLE #TMP2D8397FEAEA04F7EAC62B25A62 ([OrderID] int, [ProductID] int)
INSERT INTO #TMP2D8397FEAEA04F7EAC62B25A62 ([OrderID], [ProductID]) 
VALUES (@p0, @p1)  2 param rows
SELECT * 
FROM [Order Details] a 
JOIN [#TMP2D8397FEAEA04F7EAC62B25A62] AS b 
ON (a.[OrderID] = b.[OrderID] AND a.[ProductID] = b.[ProductID])

Requirements to the Input Parameter

To ensure the proper runtime behaviour of GetObjectsByKeys<T>(), Telerik Data Access imposes a few requirements to the input parameter:

  1. The keys enumeration has to be different then null. In case this requirement is not fulfilled the method will throw an System.ArgumentNullException exception during runtime.
  2. All the ObjectKey instances in keys should describe the identity of the T type. In case one or more of them do not meet this requirement, the method will throw a System.ArgumentOutOfRangeException exception during runtime.
  3. All the ObjectKey instances in keys should not contain version information. The opposite will cause a System.ArgumentException exception during runtime.