In this part of my WCF Data Services Custom Framework series I will implement the IUpdatable interface in our WCF Data Services container. I will do it in such a way to take advantage of the business entities and repositories created in Part 2.
The first thing we must do is to create a dictionary that can be used to store objects that need to be updated and another dictionary for objects that need to be deleted.
public partial class BusinessEntities : IUpdatable
{
public BusinessEntities()
{
}
#region IUpdatable Members
private Dictionary<object, Type> _objectsToUpdate = new Dictionary<object,Type>();
private Dictionary<object, Type> _objectsToDelete = new Dictionary<object,Type>();
Its important to have these dictionaries as an object may have several properties set and we don’t want to push changes until the object is ready to be saved. Also the reason why I use a dictionary to store the type of the object is because it is always calculated so it is a little more efficient to store the type as opposed to re-calculating it later. The next step is to implement each IUpdatable method.
- ClearChanges() – we want to cancel all the save operations.
public void ClearChanges()
{
_objectsToUpdate.Clear();
_objectsToDelete.Clear();
}
- CreateResource() – Initiate a new object for use later. We don’t have to use the default method in our repositories. Note the AddObjectToUpdate method, this method adds the object to the update dictionary (assuming it isn’t already added)
public object CreateResource(string containerName, string fullTypeName)
{
Type t = Type.GetType(fullTypeName, true);
object resource = Activator.CreateInstance(t);
AddObjectToUpdate(resource, t);
return resource;
}
- DeleteResource() – Delete the referenced object… for us that means adding it to the deletes list.
public void DeleteResource(object targetResource)
{
AddObjectToDelete(targetResource, targetResource.GetType());
}
- GetResource() – Gives a queryable that will return a single object or null. We have to use the ExecuteQuery function in the corresponding repository to find this object. The GetRepositoryOfResource() method will find the repository related to this object using reflection.
public object GetResource(IQueryable query, string fullTypeName)
{
Type t = Type.GetType(fullTypeName, true);
IBusinessRepository repo = GetRepositoryOfResource(t);
return repo.ExecuteQuery(query);
}
- GetValue() – Need to return the value of a property, just uses reflection.
public object GetValue(object targetResource, string propertyName)
{
Type type = targetResource.GetType();
return type.GetProperty(propertyName).GetValue(targetResource, null);
}
- SetValue()/SetReference() – Set a property of the given object… by doing this we are updating the object so it gets added to the list if it isn’t already
public void SetReference(object targetResource, string propertyName, object propertyValue)
{
SetValue(targetResource, propertyName, propertyValue);
}
public void SetValue(object targetResource, string propertyName, object propertyValue)
{
Type type = targetResource.GetType();
type.GetProperty(propertyName).SetValue(targetResource, propertyValue, null);
AddObjectToUpdate(targetResource, type);
}
- AddReferenceToCollection() / RemoveReferenceToCollection() – Right now I am assuming that any collection I use will implement the interface IList. These methods adds/removes an item to a list.
public void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
{
Type type = targetResource.GetType();
PropertyInfo pi = type.GetProperty(propertyName);
IList collection = (IList)pi.GetValue(targetResource, null);
collection.Remove(resourceToBeRemoved);
AddObjectToUpdate(targetResource, type);
}
public void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
{
Type type = targetResource.GetType();
PropertyInfo pi = type.GetProperty(propertyName);
IList collection = (IList)pi.GetValue(targetResource, null);
collection.Add(resourceToBeAdded);
AddObjectToUpdate(targetResource, type);
}
- ResetResource() – This is when we want to use the reset function in our repository.
public object ResetResource(object resource)
{
Type type = resource.GetType();
IBusinessRepository repo = GetRepositoryOfResource(type);
AddObjectToUpdate(resource, type);
return repo.ResetBase(resource);
}
- ResolveResource() – Simple function… we just return the object.
public object ResolveResource(object resource)
{
return resource;
}
- SaveChanges() – This is where the magic happens. We take our lists and we run them through the Save or Delete operations.
public void SaveChanges()
{
foreach (var deleteItem in _objectsToDelete)
{
var repo = GetRepositoryOfResource(deleteItem.Value);
repo.DeleteBase(deleteItem.Key);
}
foreach (var updateItem in _objectsToUpdate)
{
var repo = GetRepositoryOfResource(updateItem.Value);
repo.SaveBase(updateItem.Key);
}
ClearChanges();
}
#endregion
That’s it! The IUpdatable interface is now implemented and all object Updates/Inserts/Deletes will go through the correct business Repository. For completion I will include the code for GetRepositoryOfResource() that shows how the correct business repository is inferred using the attribute tag we gave to the business entity.
private IBusinessRepository GetRepositoryOfResource(Type resourceType)
{
var attribute = resourceType.GetCustomAttributes(typeof(BusinessRepositoryTypeAttribute), true)[0] as BusinessRepositoryTypeAttribute;
return Activator.CreateInstance(attribute.BusinessRepository) as IBusinessRepository;
}
In the next part I will use T4 to auto-generate the service items in this container so we will never have to touch the service layer again!
Print | posted on Friday, 18 June 2010 3:28 PM