🚀 Welcome to MDriven Learn –  MDriven is now on Discord!  Don’t miss the latest Release Notes.
What about HasUserCode in Enterprise Core Objects – MDriven Framework
This page was created by Alexandra on 2018-10-23. Last edited by Wikiadmin on 2026-07-29.

You can use HasUserCode on a modeled attribute when you need handwritten C# to inspect, change, or reject reads and writes of that attribute in ECO / MDriven Framework generated classes.

What HasUserCode does

HasUserCode is an attribute property in the model. Its default value is false.

When it is false, generated code reads and writes the attribute directly through the ECO object cache. This is the correct setting when no handwritten code must run when the attribute is read or written.

When it is true, the generated property includes partial-method interception points. You implement the interception point you need in your handwritten partial class. For example, you can reject an invoice due date that is less than five days after the invoice date.

Setting Generated behavior Use it when
HasUserCode = false Attribute access can go directly to the ECO cache. No C# must intercept reads or writes.
HasUserCode = true Generated property calls partial methods before and after reads and writes. You must validate, alter, observe, or prevent access to this specific attribute in handwritten C#.

Enable interception for an attribute

Assume that the model contains an Invoice class with a DueDate attribute.

  1. In the model, select the DueDate attribute.
  2. In the Object Inspector, set HasUserCode to true.
  3. Update the generated code.
  4. Open the handwritten partial-class file, for example Invoice.cs.
  5. Implement the generated partial method that matches the behavior you need.

Do not edit the framework-owned generated file, such as Invoice.eco.cs. Code generation maintains that file and can replace your changes. Put implementations in your own partial-class file instead.

What code generation changes

With HasUserCode set to false, a generated property has direct cache access:

[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)));
  }
}

With HasUserCode set to true, the generated property calls partial methods around the cache access:

[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);
  }
}

Choose the right partial method

The generator declares all four methods for an attribute whose HasUserCode is enabled. Implement only the methods your class needs.

Partial method When it runs What you can do
DueDateReading() Before the attribute value is read. Perform work that must occur before a read.
DueDateRead(ref DateTime value) After the cache value is read, before it is returned. Change the value returned to the caller.
DueDateChanging(ref DateTime value, ref bool abortModification) Before the value is stored. Change the value to be stored, or set abortModification to true to prevent the write.
DueDateChanged(DateTime oldValue, DateTime newValue, DateTime finalValue) After the value is stored. React to the completed change. oldValue is the previous value, newValue is the value requested by the caller, and finalValue is the value that was stored.

Example: reject an invalid due date

In the handwritten Invoice.cs file, implement DueDateChanging. This example prevents a due date earlier than five days after the invoice date:

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

When code attempts to assign a date that is too early, the method sets abortModification to true. The generated setter returns without storing the new value.

Performance and cache access

ECO keeps object state in a centralized cache rather than exclusively in the generated frontside object. This supports runtime behavior such as object identity handling, tracking loaded state, change signaling, and association management; see MDriven Architecture and Object Identity.

For subscriptions and expressions used by ViewModels, handles, constraints, or actions, ECO can access an attribute through this cache without routing the access through the generated frontside property. When an attribute has HasUserCode = true, ECO must route access through that property because your partial methods may affect the result or stop a change.

This routing has a small CPU cost. Enable HasUserCode when you need an interception point; leave it false for attributes that have no handwritten read or write behavior. Unimplemented partial methods are removed by the compiler, so you do not need to implement every generated interception point.

Attribute interception is not association side effects

HasUserCode on an attribute is for intercepting that attribute's reads and writes. Do not use it as a general mechanism for reacting to association changes. Associations can change from either end and through several operations. For consistent association-change handling, use the cache-hook approach described in Side effects.

Before adding imperative side-effect code, consider whether the behavior belongs in the model instead. Keep business rules declarative where possible, and use attribute interception when C# must participate in the attribute access.

See also