In my previous post I showed an interface ILockable. The actual interface is
public interface ILockable
{
Guid GetLockID();
Type GetLockObjectType();
}
Any lockable resource implements this interface. In its constructor it creates an instance of a class which descends from LockObject, a Document class for example would create an instance of DocumentLockObject which descends from LockObject. The "Document" class would store away the ID of the DocumentLockObject in a private attribute. Now when my LockingService is asked to lock multiple (un-related) instances which implement ILockable I want to do this
1: Create a new EcoSpace
2: Load objects efficiently
3: Get locks
4: Update the DB
5: Dispose of the EcoSpace
If I experience an OptimisticLockingException then loop and try again. The item I would like to discuss is #2, "Load objects efficiently". In my model a LockObject has a *–1 association to Session identifying which session has locked it, I want to ensure that the LockObject + LockObject.ExclusiveLockedSession instances are loaded as quickly as possible. If I have a collection of LockObject I can easily use the following code to efficiently load all relevant sessions
objectSpace.EnsureRelatedObjects(result, x => x.ExclusiveLockedSession);
This extension method assumes that the association name is the same as the class’s property name and is implemented like so:
public static class PersistenceServiceExtender
{
public static void EnsureRelatedObjects<T>(
this IEcoServiceProvider instance,
IEnumerable<T> objects,
Expression<Func<T, object>> member
) where T : IEcoObject
{
MemberExpression memberExpression = (MemberExpression)member.Body;
var ps = instance.GetEcoService<IPersistenceService>();
ps.EnsureRelatedObjects(objects, memberExpression.Member.Name);
}
}
This is possible because I have a list of ECO class instances as my basis and can therefore rely on the ExclusiveLockedSession association to get ECO to quickly load the related objects. The problem I need to solve is this: given an interface (ILockable) how do I get all LockObjects? Remember that these lockable objects (Document, Image, Video, etc) have no common superclass and therefore have no common association to their LockObject, and this is exactly why I wanted to know the LockObject’s primary key in my last post.
Given a collection of ILockable I am able to determine 2 things.
1: The primary key of its LockObject
2: The exact type of the LockObject it refers to (DocumentLockObject, VideoLockObject, etc).
In my new EcoSpace instance I can now inject locators for these objects directly into the cache.
private IEnumerable<LockObject> GetLockObjects(IEcoServiceProvider objectSpace, IEnumerable<ILockable> subjects)
{
//Get a reference to the cache content service so that we can inject
var cache = objectSpace.GetEcoService<ICacheContentService>();
//Create an IObjectList, a list of object locators of type LockObjecct
var variableFactoryService = objectSpace.GetEcoService<IVariableFactoryService>();
IObjectList locators = variableFactoryService.CreateTypedObjectList(typeof(LockObject), false);
//Inject each locator directly into the cache, avoiding the DB completely
foreach (var subject in subjects)
{
Guid lockObjectID = subject.GetLockObjectID();
Type lockObjectType = subject.GetLockObjectType();
IObject lockObjectLocator = cache.GetObject(lockObjectID, lockObjectType);
locators.Add(lockObjectLocator);
}
//Now I have a list of locators I can fetch the instances from
//the DB in an efficient way by converting them to IList<LockObject>
var result = locators.GetAsIList<LockObject>();
//And finally I ensure related objects
objectSpace.EnsureRelatedObjects(result, x => x.ExclusiveLockedSession);
return result;
}
Comments