You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When dealing with ChangeTrackingService and IMemento objects it's very easy to pollute the entity with ChangeTrackingService related code for the sake of simply supporting change tracking.
class Person : Entity
{
public String Name
{
get { return this.GetPropertyValue(() => this.Name); }
set { this.SetPropertyValue(() => this.Name, value); }
}
}
Things are not so easy as the graph evolves:
class Person : Entity
{
public Person(){ }
protected override void OnMementoChanged(IChangeTrackingService newMemento, IChangeTrackingService oldMemento)
{
base.OnMementoChanged(newMemento, oldMemento);
if(oldMemento !=null)
oldMemento.Detatch(this.Address);
if(newMemento !=null)
newMemento.Attach(this.Address);
}
PersonAddress _address = new PersonAddress();
public PersonAddress Address
{
get { return this._address; }
}
}
When a property is a complex type that needs to be tracked as well, the responsibility to track it is on the entity forcing the user to know change tracking details. It's even worse when dealing with setters and nullable properties:
class Person : Entity
{
public Person(){ }
protected override void OnMementoChanged(IChangeTrackingService newMemento, IChangeTrackingService oldMemento)
{
base.OnMementoChanged(newMemento, oldMemento);
if(this.Address != null)
{
if(oldMemento !=null)
oldMemento.Detatch(this.Address);
if(newMemento !=null)
newMemento.Attach(this.Address);
}
}
PersonAddress _address = new PersonAddress();
public PersonAddress Address
{
get { return this._address; }
set
{
if( this._address != value )
{
if(this.Address != null)
{
((IMemento)this).Memento.Detatch( this.Address );
}
this._address == value;
if(this.Address != null)
{
((IMemento)this).Memento.Attach( this.Address );
}
}
}
}
}
The exact same problem applies to collections. That are basically complex IMemento types.
Ideas
AutoTrack
One option could be to inspect the graph when the tracking process starts, e.g. by doing:
var person = new Person();
memento.Attach( person, new TrackingOptions
{
AutoTrack = true
} );
The above asks the ChangeTrackingService to scan the incoming graph, Person instance in this case, and automatically attach memento properties. If the entity is Entity (and we could enforce it) we can detect when properties change, get old and new value and automatically handle all the above scenarios.
Static Track Definition
One of the issues with the AutoTrack feature is for example detect circular references, another option could be (not mutually exclusive) to allow users to define statically what to track:
var person = new Person();
memento.Attach<Person>( person, new StaticTrackDefinition<Person>()
{
Properties = new []{ p => p.Address }
} );
(the above syntax is invalid, it's just to give the idea)
The static approach complicates a lot things when it comes to complex graphs whose depth is more than 2 levels:
Order
Rows
OrderItem
ProductDefinition
PriceDefinition
...
If all the elements in the graph are IMemento instances manually defining what to track is awful.
Roslyn
Last option that comes to my mind is that the plumbing code could be written in the entity class via Roslyn at compile time. It can be super complex but it's an option.
Notes
This should not be the default behavior, users opt-in at Attach time. Obviously detaching a graph should do the reverse and detach all the auto-attached children.
The text was updated successfully, but these errors were encountered:
Problem
When dealing with
ChangeTrackingService
andIMemento
objects it's very easy to pollute the entity withChangeTrackingService
related code for the sake of simply supporting change tracking.The basic usage on a flat entity is trivial, theoretically we could improve it via Roslyn, the only requirement is to use the Radical property system:
Things are not so easy as the graph evolves:
When a property is a complex type that needs to be tracked as well, the responsibility to track it is on the entity forcing the user to know change tracking details. It's even worse when dealing with setters and nullable properties:
The exact same problem applies to collections. That are basically complex
IMemento
types.Ideas
AutoTrack
One option could be to inspect the graph when the tracking process starts, e.g. by doing:
The above asks the
ChangeTrackingService
to scan the incoming graph,Person
instance in this case, and automatically attach memento properties. If the entity isEntity
(and we could enforce it) we can detect when properties change, get old and new value and automatically handle all the above scenarios.Static Track Definition
One of the issues with the
AutoTrack
feature is for example detect circular references, another option could be (not mutually exclusive) to allow users to define statically what to track:(the above syntax is invalid, it's just to give the idea)
The static approach complicates a lot things when it comes to complex graphs whose depth is more than 2 levels:
If all the elements in the graph are IMemento instances manually defining what to track is awful.
Roslyn
Last option that comes to my mind is that the plumbing code could be written in the entity class via Roslyn at compile time. It can be super complex but it's an option.
Notes
This should not be the default behavior, users opt-in at
Attach
time. Obviously detaching a graph should do the reverse and detach all the auto-attached children.The text was updated successfully, but these errors were encountered: