Telerik blogs

As existing users might have experienced , handling the identity of a persistent object in OpenAccess can get complicated at times especially when it comes to a type with composite identity fields. With an aim to simplifying this aspect we worked on the ObjectKey API to make it easier to comprehend and to use. This blog post describes the API in brief, it’s intended usage and how existing code can be migrated.

 

The ObjectKey

The ‘ObjectKey’ is the new entry point for working with a persistent object’s identity. The ‘ObjectKey’ for a persistent object can be obtained form the runtime or if you know the persistent  type and it’s identity values, you can create an ‘ObjectKey’ instance to load the object from the datastore. Lets demonstrate this with some code -

Obtaining an ObjectKey

   1: OrderDetail orderDetail = context.OrderDetails.Where(od => od.Quantity > 10).First();
   2: ObjectKey objectKey = ObjectKey.Create(orderDetail);
   3: ObjectKey objectKeyUsingCtx = context.CreateObjectKey(orderDetail);

As demonstrated above, you can obtain an ‘ObjectKey’ from an existing persistent object by using the static method of the ObjectKey class - ‘Create(object entity)’ or the equivalent method on the context class – ‘CreateObjectKey(object entity)’.  The returned key contains a key/value pair (an instance of ObjectKeyMember) for each identity member of the persistent type where the key is the property name of the identity member. You can obtain the individual identity value by enumerating the ‘ObjectKeyValues’ property of the key.

There might be situations where you do know the type of the persistent entity and it’s identity values, typically as parameters of a web request, and would actually like to load the object from the datastore. This can be achieved with just couple of lines of code as follows -

Obtaining a persistent object

   1: ObjectKey key = new ObjectKey("Northwind.Customer", "ALFKI");
   2: var customer = context.GetObjectByKey<Customer>(key);

It’s as simple as that. All you need to do is specify the unambiguous name of the persistent type (the name should resolve to a unique  persistent type in the domain model) and the value of the identity member. In case you have a persistent type with multiple identity members you can specify key/value pairs for each identity members. Here’s how -

Obtaining a persistent object with multiple identity members

   1: ObjectKey key = new ObjectKey("Northwind.OrderDetail", new[] {
   2: new KeyValuePair<string, object>("OrderID", 10248), 
   3: new KeyValuePair<string, object>("ProductID", 11) });
   4: var OrderDetail = context.GetObjectByKey<OrderDetail>(key);

 

The ‘ObjectKey’ can additionally store the version information about a particular persistent instance. Such a key can be used to obtain an object that has exactly the same identity and version as specified by the key. A versioned key can be obtained from an existing entity as follows -

Obtaining an ObjectKey with version information

   1: OrderDetail orderDetail = context.OrderDetails.Where(od => od.Quantity > 10).First(); 
   2: ObjectKey keyWithVersion = ObjectKey.CreateWithVersion(orderDetail);     
   3: ObjectKey keyWithVersionFromCtx = context.CreateObjectKeyWithVersion(orderDetail);

The two methods demonstrated above are equivalent and any one of them can be used. The versioned key contains a key/value pair for each member that participates in a optimistic concurrency check. This could be a single field if the concurrency strategy  is -  ‘OptimisticConcurrencyControlStrategy.Version’ or multiple fields if it is ‘OptimisticConcurrencyControlStrategy.Changed’.

 

Consider the case where you try to load an object with a certain version (using a versioned key) and it cannot be found since it was modified in the meantime and now has a newer version. You might want to handle this case by displaying an appropriate message and then obtaining the available object anyways. Here is some code showing how you could do that.

Obtaining an object using a versioned key

   1: ObjectKey keyWithVersion = context.CreateObjectKeyWithVersion(customer);
   2: //
   3: //
   4: Customer customer = null;
   5: try
   6: {
   7:     customer = otherContext.GetObjectByKey<Customer>(keyWithVersion); //use a versioned key obtained previously.
   8: }
   9: catch (OptimisticVerificationException cce)
  10: {
  11: //display a message and then try and get it without the version
  12:     customer = context.GetObjectByKey<Customer>(keyWithVersion.GetWithoutVersion());
  13: }

The ‘GetObjectByKey’ method and it’s variations (GetObjectByKey<T>, TryGetObjectByKey<T>) will try to load the object from the datastore by taking into consideration it’s version, if the specified key has version information. If you would like to ignore the version information you can obtain a non-versioned key from a versioned key using the ‘ObjectKey.GetWithoutVersion’ method.

In case you want to avoid catching the OptimisticVerificationException as shown in the above example, you can use the ‘TryGetObjectByKey’ method. This method will return false in case an object with the specified key is not found.

Using TryGetObjectByKey

   1: ObjectKey keyWithVersion = context.CreateObjectKeyWithVersion(customer);
   2: //
   3: Customer customer = null;
   4: if(otherContext.TryGetObjectByKey<Customer>(keyWithVersion,out customer) == false) //use a versioned key obtained previously.
   5: {
   6: //object is not found.Display a message and try and get it without a version check.
   7: if(keyWithVersion.HasVersion)
   8:     {
   9: if(otherContext.TryGetObjectByKey<Customer>(keyWithVersion.GetWithoutVersion(),out customer) == false)
  10:         {
  11: //object with specified identity is not present in the datastore
  12:         }
  13:     }
  14: }

 

To achieve this simplicity in the ObjectKey API it was necessary to remove certain methods (or mark them as obsolete) that dealt with the  ObjectKey. For instance, all methods to obtain an object from a key that accepted a ‘bool’ parameter for version checks have now been removed. As mentioned previously the version check is now implicitly done based on the specified key. Here is how you can migrate such code.

   1: ObjectKey keyWithVersion = context.CreateObjectKey(customer,true);
   2: //...
   3: var cust = context.GetObject<Customer>(keyWithVersion,true);
   4:  
   5: //The above lines can be replaced with..
   6: ObjectKey keyWithVersion = context.CreateObjectKeyWithVersion(customer);
   7: var cust = context.GetObjectByKey<Customer>(keyWithVersion);

 

You can find more information about the ObjectKey and its usage in the documentation.

This has been a major step towards simplifying the API and we hope you enjoy the experience.


About the Author

Jan Blessenohl

Product Manager,
OpenAccess ORM Team

Comments

Comments are disabled in preview mode.