The documentation comes from the Markdown files in the source code, so is always up-to-date but available only in English. Enjoy!
One reson we don't support POCO (saving and retrieving object not inheriting from Entity), is that the CLR has no infrastructure for knowing what properties have changed in an object from a given start moment.
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 then you need to attach/detach entities and you loose the nice static class Database)
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 behavior by keeping track of the modified fields , and it's the class we are going to focus on here.
See more about the hierarchy in Base Entities.
Basically Modifiable contains the property Modified of type ModifiedState. The possible values are:
SelfModified: The object itself has been modified.Clean: The object has not been modified. If checked during Saving event it also means no (recursively) child has changes either.Modified: The object itself has not changes, but some (recursively) child is SerfModified.Sealed: The object has been retrieved in a Sealed context, so any attempt to modify it will throw an exception. Useful for shared caches.ModifiableEntity has four main responsibilities about change tracking:
Modifiable.Modified property.INotifyPropertyChanged interface. Mainly for WPF's Binding infrastructure, so it raises an event when a property has changed.protected Set method.Also, ModifiableEntity implements IDataErrorInfo interface for validation (See more in Validation), and implements IClonable explicitly.
INotifyPropertyChanged interface is the standard interface since .Net Framework 2.0 for exposing an event when some properties have changed. This is useful for data-binding scenarios.
Notify method allows you to invalidate a property manually (usually in order to notify affected validations)
class ModifiableEntity
{
public void Notify<T>(Expression<Func<T>> property)
}The method is strongly typed, taking an expression instead of a string
//So instead of writing
Notify("Name");
//We write
Notify(() => Name);In order to notify changes in ToString property, NotifyToString can also be used.
The Set method is used in any property setter:
protected virtual bool Set<T>(ref T field, T value,
[CallerMemberNameAttribute]string automaticPropertyName = null)The simple Set method has a lot of competences:
field is equal to value, returning false in this case.field.SelfModified
field = value.field.automaticPropertyName property.Error property (from IDataErrorInfo).Notice that automaticPropertyName is meant to be used in the property setter and in this case the value is automatically filled by the C# compiler thanks to CallerMemberNameAttribute. If used elsewhere has to be set explicitly.
If the property will affect the entity ToString, SetToStr can be used instead:
//instead of
set { if(Set(ref name, value, "Name")) NotifyToString(); }
//you can write
set { SetToStr(ref name, value, "Name")); }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.
Attaching and detaching the events is cumbersome:
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.
NotifyPropertyChanged and NotifyCollectionChanged facilitate your life using a declarative approach for attaching events to sub-entities in a similarly to VisualBasic's WithEvents.
Place a NotifyPropertyChangedAttribute attribute over the field you are interested in, then override ChildPropertyChanged like this:
public class SchoolEntity: Entity
{
string name;
(...)
[NotifyPropertyChanged]
PersonEntity director;
(...)
protected override void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(sender == director && e.PropertyName == "Name")
{
name = director.Name + "'s School";
}
}
}Place a NotifyCollectionChangedAttribute over the field you are interested in, then override ChildCollectionChanged like this:
public class SchoolEntity: Entity
{
decimal stateFunds;
(...)
[NotifyCollectionChanged]
MList<PersonEntity> students;
(...)
protected override void ChildCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
if(sender == students)
{
stateFunds = students.Count * FundsPerStudent;
}
base.ChildCollectionChanged(sender, args);
}
}Place a NotifyCollectionChangedAttribute and NotifyPropertyChangedAttribute attribute over the field of the collection you are interested in, then override ChildPropertyChanged like this:
public class SchoolEntity: Entity
{
decimal stateFunds;
(...)
[NotifyCollectionChanged, NotifyCollectionChanged]
MList<PersonEntity> students;
(...)
protected override void ChildCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
if(sender == students)
{
stateFunds = students.Count * FundsPerStudent;
}
base.ChildCollectionChanged(sender, args);
}
}© Signum Software. All Rights Reserved.
Powered by Signum Framework