Sunday, January 16, 2011

What about HasUserCode in Enterprise Core Objects – ECO the Model Driven Framework

Class Attributes in classes modeled with ECO has a property called HasUserCode. This post sets out to explain what effect the property has and what the intended use is.

Let us say that we have this model:

image

Focus the DueDate attribute and look at the Object inspector:

image

By default the HasUserCode property is false – this says that there are NO side effects or checks applied in code that influence or stop anyone from having the value set.

Let us generate the code:

image

The Invoice class is implemented as a partial class were Invoice.cs is yours and Invoice.eco.cs is maintained by the Framework.

Open up the Framework owned Invoice.eco.cs and look at the attribute definition:

[UmlElement(Id="256adf06-35be-47e7-9189-e882c4bb779f", Index=Eco_LoopbackIndices.DueDate)]
public System.DateTime DueDate {
  get {
    return ((System.DateTime)(this.eco_Content.get_MemberByIndex(Eco_LoopbackIndices.DueDate)));
  }
  set {
    this.eco_Content.set_MemberByIndex(Eco_LoopbackIndices.DueDate, ((object)(value)));
  }
}

As you can see there is no room for extravaganza while setting or reading the attribute “DueDate”.

Let us set HasUserCode to true for the DueDate attribute in the model – update the code and look at the Framework owned file again:

[UmlElement(Id="256adf06-35be-47e7-9189-e882c4bb779f", Index=Eco_LoopbackIndices.DueDate)]
[UmlTaggedValue("Eco.HasUserCode", "True")]
public System.DateTime DueDate {
  get {
    this.DueDateReading();
    System.DateTime res = ((System.DateTime)(this.eco_Content.get_MemberByIndex(Eco_LoopbackIndices.DueDate)));
    this.DueDateRead(ref res);
    return res;
  }
  set {
    System.DateTime oldValue = this.DueDate;
    System.DateTime newValue = value;
    bool abortModification = false;
    this.DueDateChanging(ref value, ref abortModification);
    if (abortModification) {
      return;
    }
    this.eco_Content.set_MemberByIndex(Eco_LoopbackIndices.DueDate, ((object)(value)));
    this.DueDateChanged(oldValue, newValue, value);
  }
}

Notice the difference. We now have calls to DueDateReading, DueDateRead, DueDateChanging, DueDateChanged.

These are all Partial Methods declared by the framework. Partial method is a .net language construct that is perfect for Frameworks like ECO to use. ECO added these definitions to the Invoice class:

#region *** DueDate partial methods ***
 
/// <summary>This method is called before the attribute DueDate is read</summary>
partial void DueDateReading();
 
/// <summary>This method is called after DueDate is read. It is possible to change the value here.</summary>
partial void DueDateRead(ref DateTime value);
 
/// <summary>This method is called before DueDate is modified, it is possible to change the value that is stored here or abort the modification</summary>
partial void DueDateChanging(ref DateTime value, ref bool abortModification);
 
/// <summary>This method is called after DueDate is modified</summary>
/// <param name="oldValue">This is the value that DueDate had before the modification</param>
/// <param name="newValue">This is the value that someone tried to set</param>
/// <param name="finalValue">This is the value that DueDate has after the modification</param>
partial void DueDateChanged(DateTime oldValue, DateTime newValue, DateTime finalValue);
 
#endregion *** DueDate partial methods ***

You – as the developer – may need only one or two of these interception points – but ECO gave you all. Unused Partial Methods are however stripped by the compiler and cost you nothing in runtime.

Now we can head back to Invoice.cs – the implementation file that you use and the framework does not touch:

public partial class Invoice {
}

Very empty so far but we can now implement one of the interception points. Just write “partial” and see what comes up:

image

Pick the one you want and add your stuff:

partial void DueDateChanging(ref DateTime value, ref bool abortModification)
{
    if (value < this.Date.AddDays(5))
        abortModification = true;
}

Why not do this all the time?

The normal question after having explained HasUserCode is “Why would you ever want to turn HasUserCode off?“. It is a relevant question since the partial methods does not cost anything in runtime – we might as well leave the HasUserCode on all the time… Or?

The question is slightly more complex. ECO has the ambition to be as effective as possible and always use the most efficient way to get things done. As a result of this all the internal state of objects is not stored in the frontend object as such but in a centralized cache. This strategy gives us advantages on many levels – like holding object identities before they are fully loaded, knowing what we have loaded or not, signaling changes, ensuring association ends even if not completely loaded, execute models without generated code etc , etc.

So when following expressions for subscriptions – created automatically or explicitly, or expressions from ViewModels, Handles, Constraints or Actions – ECO does not really need to route the call thru the frontend object – it can head straight for the cache and cut a few cpu cycles from the workload – it might not be much but since Eco is a Framework these things add up and become important.

UNLESS the read or written attribute has the HasUserCode flag set – if it has ECO will always route access thru the frontside object.

So does this mean that HasUserCode==true makes my code slower? Technically yes – it will cost you a couple of cpu cycles – so “a lot slower?” No!. You should not worry about that if you need the interception points – but you should leave HasUserCode set to false if you have no intention of using the interception points.

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home

 
Contact Us | Terms of Use | Privacy Statement © 2009 CapableObjects