Signum Framework Logo
"Open framework that encourages convention over configuration, using C# code,
not XML files, to model at the right level of abstraction and achieve deadlines.
...but also has a full Linq provider, and syncs the schema for you!"
Login
RSS

Search

»



Main
Index
Map
Videos
Download
Source code
Tutorials
Forum
FAQ



Image



PoweredBy


Introduction

The main reason we don't support POCO (Saving and retrieving objects already made by you before you fell in love with ever knew Signum Framework existed), is that the CLR has no infrastructure for knowing what properties have changed in an object from a given 'start' moment. Also we wanted to have a unified int Id for any object, but that's another thing.

Not having embedded change tracking means that you have to save the whole object all the time. And since we work mainly with full graphs of objects, that would mean saving the whole graph. Just for a single update. (We could do change tracking in a separated session/DataContext object instead, but we avoid that in favour of a static Database class)

The basic responsibility for a Modifiable class, the root of any entity related object, is to have a unified model for the Engine to know about change tracking, there are three implementations:

  • MList<T> implements Modifiable behaviour, but it's better explained in it's own page.

  • Lite<T> has a degenerated Modifiable behaviour, since is semantically immutable (Fatness and Thinness doesn't affect to the meaning of the Lite). See more about Lite.

  • Finally, ModifiebleEntity implements Modifiable behaviour in a field-centric fashion and it's the class we are going to focus on here.

See more about the hierarchy in Base Entities.

ModifiableEntity and change tracking

ModifiableEntity has four three main responsibilities about change tracking:

  1. Implementing change tracking in the way Modifiable class like.
  2. Implementing INotifyPropertyChanged interface. Mainly for WPF's Binding infrastructure, so it knows when a property has changed.
  3. Facilitating child change notifications in a declarative fashion. Mainly for Validation.
  4. Allowing derived classes to do the last three things using a convenient protected Set method.

Also, ModifiableEntity implements IDataErrorInfo interface for WPF's compatible validation (See more in Validation), and implements IClonable explicitly.

Implementing Modifiable behaviour

Modifiable is a very easy-to-derive class. It contains two main properties, Modified and SelfModified. Modified is backed by its own modified field, while SelfModified is for the derived classes to implement.

In this case ModifiableEntity implements it, just backing it with another field, SelfModified. That starts as false but it's changed to true when a field is changed to a different value. Since it isn't possible to intercept field changes we have to call Set method in every single set block of our entity properties.

The relationship between Modified and SelfModified is the following: GraphExplorer static class has a method, PropagateModifications that propagates every general Modifiable changes (SelfModified == true) to its container IdentifiableEntity (Modified = true). See more about Entity Graphs and Database - Save

Implementing INotifyPropertyChanged

INotifyPropertyChanged interface is the standard interface since .Net Framework 2.0 for exposing an event when some of your properties have changed. This is primarily useful for databinding scenarios of any kind.

NotifyPrivate (string based)

Internally you have the NotifyPrivate method that is implemented like this:

  protected void NotifyPrivate(string propertyName)
  {
     if (PropertyChanged != null)
         PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  }

So you can call it whenever you think you should notify about a change of a property.

Notify has now been renamed to NotifyPrivate and is the only string based method related to properties. All the rest use strong-typed reflection in the new version.

Notify (strongly typed)

In order to avoid referring to the property using a error-prone propertyName string literal (no Compile-time checking, no IntelliSense, no Refactoring) the rest of the methods use compiler-generated expression trees. For example, Notify protected method look like this:

//instead of
protected void Notify<T>(Expression<Func<T>> property)

Example:

//So instead of writing
Notify("Name");
//We call
Notify(()=>Name);

This technique is called strong-typed reflection, and has been slightly optimized to have a better performance (no boxing node) and sort enough (just 2 characters longer!), so This is the preferred way to notify about properties.

Very often you have to notify about ToStringMethod to notify the WPF infrastructure that ToString has changed, in order to do so use Notify(()=>ToStringMethod).

NotifyErrors has been removed and NotifyToString has been deprecated in favor of Notify(()=>ToStringMethod) or just SetToStr.

Set

This convenient method does three things that most of the property setters have to do:

  • Change the value of the underlying field.
  • Notify that the current property have changed
  • Know if the value have actually changed (in case you want to do something else).

protected virtual bool Set<T>(ref T variable, T value, Expression<Func<T>> property)

As you see, it does all the magic for you, and keeps your code simple:

int age;
public int Age
{
    get { return age; }
    set { Set(ref age, value, "Age"); }
}

This little thing is what makes Signum Entities much easier to read that Microsoft's auto generated code.

As you see, set method now uses strongly-typed reflection to refer to the property and the previous overload has been removed. In case you need to migrate many entities from SF 1.0 to SF 2.0 use this replacement Regex in Visual Studio Find and Replace dialog.
Find what: Set\(ref {:i}, value, \"{:i}\"\)\;
Replace with: Set(ref \1, value, () => \2);

Also, there's a SetToStr set method for changing properties that affect ToString (and ToStringMethod property) in a slighlty easier way.

  public bool SetToStr<T>(ref T variable, T value, Expression<Func<T>> property)
  {
     if (this.Set(ref variable, value, property))
     {
        NotifyPrivate("ToStringMethod");
        return true;
     }
     return false;
  }

Example

string name;
public string Name
{
   get { return name; }
   set { Set(ref name, value, "Name"); }
}

(...)

public override string ToString() { return name; }

This way the title is correctly update in the title or in a master-detail in WPF.

Facilitate Child Change Notifications

With INotifyPropertyChanged our entities are able to notify the world in the exact moment some property changes, but sometimes what you want is for your entities to get events from their sub-entities in order to make real-time validations on sub-entities or calculate redundant values.

Usually you do so wiring the events, but this is a bit of a pain in the ass:
  • Wire every time the entity is retrieved.
  • Wire every time the sub entity changes, and unwire the old one.
  • Since the event could be attached to WPF or any other object, the event delegate field has to be marked as NonSerialized and also as Ignore. So you have to wire it back after deserializing the full graph.

The above is also applicable to sub-collections using INotifyCollectionChanged instead.

So we facilitate your life using a declarative approach for attaching events to sub-entities in a similar way to VisualBasic's WithEvents.

For Sub-Entities

Place a NotifyPropertyChangedAttribute attribute over the field you are interested in, then override ChildPropertyChanged like this:

public class SchoolDN: Entity
{
    string name; 
    (...)

[NotifyPropertyChanged] PersonDN director; (...)

protected override void ChildPropertyChanged(object sender, PropertyChangedEventArgs e) { if(sender == director && e.PropertyName == "Name") { name = director.Name + "'s School"; } } }

ChildItemPropertyChanged renamed to ChildPropertyChanged

For Sub-Collections

Place a NotifyCollectionChangedAttribute over the field you are interested in, then override ChildCollectionChanged like this:

public class SchoolDN: Entity
{
    decimal stateFunds; 
    (...)

[NotifyCollectionChanged] MList<PersonDN> students; (...)

protected override void ChildCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) { if(sender == students) { stateFunds = students.Count *FundsPerStudent; } } }

For Sub-Entities in Sub-Collections Image

Place a NotifyPropertyChangedAttribute attribute over the field of the collection you are interested in, then override ChildPropertyChanged like this:

public class SchoolDN: Entity
{
    decimal stateFunds; 
    (...)

[NotifyCollectionChanged] MList<PersonDN> students; (...)

protected override void ChildPropertyChanged(object sender, PropertyChangedEventArgs e) { if(sender is PersonDN && students.Contains(person) && e.PropertyName == "Age") { avgAge = students.Avg(s=>d.Age); } } }

Sweet, isn't it?

Creative Commons License Signum Framework Site by Signum Software is licensed under a Creative Commons Attribution 3.0 License.
Powered by ScrewTurn Wiki version 3.0.5.600.