Telerik blogs

How to get objects into the ObjectContainer?


The ObjectContainer contains a closed world of instances, no reference is dangling and pointing out of the container. That means, the instance graph is contained completely in this 'workspace'. Of course, at some points the need arises to prune the graph, as otherwise the whole database content would need to be stored in the containers memory. This is no different to the connected IObjectScope, but in the scope, we can directly perform the loading of objects from the database (lazy loading).
With the container, there is no connection to a database, hence no support for automatic lazy loading. There is a way to perform that programmatically, however; I will
show that later.

 

To fill the container with a set of existing objects that should be made available to a disconnected tier, the ObjectContainer.CopyFrom(IObjectScope scope, string name, object instance, IObjectCollector collector) is to be used. With this method the instance and all instances reachable by the given object collector are copied to the ObjectContainer and tagged under the given name. The tag can later be used to find the instance(s) back in the container. You can copy from the IObjectScope multiple times to the same ObjectContainer; if an already copied object was changed in mean time, it is overwritten with the newer values.

 

Completely new instances can also be added to an ObjectContainer on a remote tier. The API for that should look familiar; just use ObjectContainer.Add(object). Likewise, instances
can be marked as to be deleted with ObjectContainer.Remove(object). These are methods that are common between the ObjectContainer and the IObjectScope; the same applies to
the GetObjectId(object) / GetObjectById(IObjectId) methods and the Transaction property. All the Add() and CopyFrom() methods assume, that the set of objects that is to be used
on the remote disconnected tier is known in advance, like in an offloaded calculation. Many times though, you will need to follow a reference to an object that was not loaded
yet into the container.

Let's assume you need to access an Address instance from a Person that was copied and the Address wasn't. Per default, the Address instance is in a 'hollow' state; that is, the instance is there, but the data isn't. You will get an exception when attempting to access a hollow field. As I said before, the graph will be pruned at some point...


But there is a way to get the data transparently, and that involves setting up a handler and a way to physically obtain the missing data. The handler must be set as the ResolveProxy event handler for the ObjectContainer, and this handler must know how to obtain the connected data. This is the place where you must put in your knowledge ... so I will leave this out for now.
Here is how it could look like to access the street name of the main address from a person and loading the address object data via the proxy resolve handler:

 

       public string StreetNameAccessExample(IObjectScope scope)
       
{
           
ObjectContainer oc = new ObjectContainer();

           
// Copying some content into the container
            var me = scope.Extent<Person>().First(p => p.Name == "Thomas");
           
oc.CopyFrom(scope, "x", me, null);
           
// container is filled now.

           
IObjectId oid = scope.GetObjectId(me);

           
oc.ResolveProxy += ResolveProxyHandler; // allows for dynamic lookup of missing (hollow) data.

           
// could also use the 'x' list to find me again.
            Person x = (Person)oc.GetObjectById(oid); 

           
return x.MainAddress.StreetName; // Here the handler is invoked ++++
       
}

       
void ResolveProxyHandler(object sender, ObjectContainer.ResolveProxyEventArgs e)
       
{
           
// Typically, the event args are transported to the service
            // and used there to fill up the req container with data from an object scope.

           
ObjectContainer req = new ObjectContainer();
           
foreach(var oid in e.ProxyIdentity)
           
{
               
req.CopyFrom(Scope,"y",Scope.GetObjectById(oid),null);
           
}
            
           
// Transport from the server to the client occurs; left out here.
            ObjectContainer oc = (ObjectContainer) sender;

           
// Apply the freshly obtained data into the existing ObjectContainer.
            oc.Apply(req.GetChanges(ObjectContainer.Verify.All));
       
}

 

Our ResolveProxyHandler is invoked transparently in the line marked with ++++. The code for going to the service (layer, provider, tier) has been left out here for clarity reasons. The handler resolves the one missing object (whose identity is transported with the event args instance) and makes the data available; then the StreetName property getter method returns.

Do not overuse this feature however, as it will lead to a C/S call every time an object is missing, transparently.

 

Stay tuned for more on the ObjectContainer …


Comments

Comments are disabled in preview mode.