Posts

Showing posts from April, 2009

Injecting into the ECO cache

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

Setting the ID of an ECO object before it is saved

This might seem like a bit of an odd requirement. I am currently implementing an offline pessimistic locking service in an ECO app. This will mean that I can use a LockingService to place read/write locks on objects. As usual I have gone for an interface approach (ILockable) rather than making all my lockable classes descend from a base Lockable class. Remember, it's what I DO , not what I AM . The idea is that I have a Lockable object which holds a list of Sessions. These Sessions indicate who has a read lock, and who has a write lock on the object. Each ILockable business entity will create its own private instance of Lockable when it is created. The thing is, this application will at times need to lock thousands of objects in as little time as possible. As there is no common ancester for these ILockable classes I can't just use EnsureRelatedObjects to traverse an association name and load all LockObject instances in a single select. I decided that what I needed was

Using a GUID as the key in ECO

Drop a DefaultORMappingBuilder component next to your persistence mapper. Point PersistenceMapperxxxxx1.NewMappingProvider and RuntimeMappingProvider to point to this new component. On your PersistenceMapper component expand SqlDatabaseConfig and click the [...] next to KeyMappers, ensure that you have an item named "GuidMapper" with the MapperTypeName set to "Eco.Persistence.GuidKeyMapper". If not then add it. On your DefaultORMapperBuilder set IdKeySignature to System.Guid (case sensitive). Set its IdMapperName to GuidMapper. Now regenerate your DB.

Prism AOP - 4

I’ve played a little more with Prism. I find it a little difficult to mentally code on two levels. Level one being the code I am writing for the aspect, and level two being the code I am writing which will executed by the target. Having said that, as soon as I ran my app and saw the output everything was worthwhile. Here is my Person class type   [aspect: EcoAspects.BusinessClass(’DomainClasses.Package1’)]   Person = public class   private     FFirstName: String;     FLastName: String;   protected   public     property FirstName : String read FFirstName write FFirstName;     property LastName : String read FLastName write FLastName;   end; here is the code which uses that class class method ConsoleApp.Main; var   P: Person; begin   P := new Person();   for A in typeOf(Package1).GetCustomAttributes(true) do     Console.WriteLine(a.ToString());      P.FirstName := ’Peter’;   P.LastName := ’Morris’;   ShowGetValueByIndexResult(P as ILoopBack2, 0);   ShowGetValueByIndexResult(P as

ECO – Ensure related objects

Sometimes you have a list of objects (say List<PurchaseOrder>) and you want to get all associated objects (say OrderLines) for all the orders in the list. There are 2 ways of doing this in ECO You call a PersistenceService method which takes the list of orders and a string identifying the association name. I don't like this approach because the name of the association may change during modelling and this wont be picked up as an error until runtime. You use the overloaded method which takes an IAssociationEnd. I don't like this either because you have to find the IAssociationEnd instance from the meta-model at runtime, and to do this you'd probably use a name anyway. So, what's the alternative? public static void EnsureRelatedObjects<T>(this IPersistenceService instance, IEnumerable<T> objects, Expression<Func<T, object>> member) where T : IEcoObject {     MemberExpression memberExpression = (MemberExpression)member.Body;     instance.Ensu

Prism AOP - 3

I am playing with Prism’s new Aspect Oriented Programming feature. As a learning exercise I am implementing some of the features ECO requires on a class. If all goes well I will end up with aspects I can apply to plain classes and have them run in ECO. One of those features is the ILoopBack2 interface. In order to tackle this interface a small piece at a time I have created my own ILoopBack2 interface, so far with only one method. ILoopBack2 = public interface   function GetValueByIndex(I: Integer): System.Object; end; This method allows the ECO to evaluate OCL (Object Constraint Language) expressions such as "self.FirstName" and have them route via the class’s property, just in case there is any logic in the getter. By implementing an interface which uses an index to identify the property to read it is possible to avoid reflection. So, getting on with it, here is my class definition type   [aspect: EcoAspects.BusinessClass(’DomainClasses.Package1’)]   Person = publ

AOP 2

This is fun :-) I’ve created an aspect like so type   BusinessClassAttribute = public class(System.Attribute, ITypeInterfaceDecorator)   private     FPackageName: String;     property PackageName: String read FPackageName;   protected   public     constructor (PackageName: String);     method HandleInterface(Services: RemObjects.Oxygene.Cirrus.IServices; aType: RemObjects.Oxygene.Cirrus.ITypeDefinition);   end; I can now decorator my class like so type   [aspect: BusinessClass(’DomainClasses.Package1’)]   Person = class   end; I can ensure this class  exists in the aspect implementation method. constructor BusinessClassAttribute(PackageName: String); begin   FPackageName := PackageName; end; method BusinessClassAttribute.HandleInterface(Services: RemObjects.Oxygene.Cirrus.IServices; aType: RemObjects.Oxygene.Cirrus.ITypeDefinition); var   PackageType: ITypeReference; begin   PackageType := Services.FindType(PackageName);   if (PackageType = nil) then     Services.EmitError(’Pac

My first AOP

Here’s what I did. 01: I created a support project which just has a logger class in it. namespace EcoSupport.pas; interface uses   System.Collections.Generic,   System.Linq,   System.Text; type   Logger = public class   private   protected   public     class procedure Log(Message : String);   end; implementation class procedure Logger.Log(Message : String); begin   System.Diagnostics.Debug.WriteLine(’Log: ’ + Message); end; end. 02: I created an Aspect which decorates methods, giving me the opportunity to intercept all method calls on the class it decorates. namespace EcoAspects; interface uses   System.Collections.Generic,   System.Linq,   System.Text,   RemObjects.Oxygene.Cirrus,   EcoSupport; type   [AttributeUsage(AttributeTargets.Class)]   LogAspect = public class(System.Attribute, RemObjects.Oxygene.Cirrus.IMethodImplementationDecorator)   private   protected   public     method HandleImplementation(Services: IServices; aMethod: IMethodDefinition);   end; implementa