This question is locked. New answers and comments are not allowed.
Hi.
I'm looking to implement the IEditableObject interface in a base persistent class, so that all descendants would automatically benefit from this implementation. Could you please give some pointers on how to achieve this, if possible?
Most important is of course offline usage, where ObjectContainer is involved rather than ObjectScope.
Typically usage is when an object is bound to a form with 'OK' 'Cancel' 'Apply' buttons. But also in grids etc.
Maybe IObjectContext methods could be used, since they are shared between IObjectContainer and IObjectScope.
Any feedback or thoughts would be much appreciated.
Thanks
Pål
I'm looking to implement the IEditableObject interface in a base persistent class, so that all descendants would automatically benefit from this implementation. Could you please give some pointers on how to achieve this, if possible?
Most important is of course offline usage, where ObjectContainer is involved rather than ObjectScope.
Typically usage is when an object is bound to a form with 'OK' 'Cancel' 'Apply' buttons. But also in grids etc.
Maybe IObjectContext methods could be used, since they are shared between IObjectContainer and IObjectScope.
Any feedback or thoughts would be much appreciated.
Thanks
Pål
3 Answers, 1 is accepted
0
Hi Pål,
It is not possible at the moment to really roll back the changes. This is exactly the missing part to support nested transactions.
What you can do in your base class implementation is a refresh in case of scope and a Server call with the id to get the data again from the db and Apply() it to the container.
Sincerely yours,
Jan Blessenohl
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
It is not possible at the moment to really roll back the changes. This is exactly the missing part to support nested transactions.
What you can do in your base class implementation is a refresh in case of scope and a Server call with the id to get the data again from the db and Apply() it to the container.
Sincerely yours,
Jan Blessenohl
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
0
Pål
Top achievements
Rank 1
answered on 13 Mar 2010, 09:14 PM
Hi Jan.
I was afraid that was the case...
I'm also afraid your solution will not completely satisfy the IEditableObject interface: When a call to BeginEdit() is made on an already dirty instance, CancelEdit would then return the instance to the persistent state rather than the pre-BeginEdit() state.
I have found a solution which will work, but will also make unnecesary calls to the backend storage / business layer since a property will always be marked as dirty event if the original value is re-set. So my next question then is: Can you mark a property non-dirty. E.g.. IObjectContext.MakeNonDirty(String propertyName)? I'm completely happy using reflection for this...
Here is my IEditableObject implementation. A very crude implementation using reflection to create a snapshot of all read/write properties at BeginEdit() call:
Thanks
Pål
I was afraid that was the case...
I'm also afraid your solution will not completely satisfy the IEditableObject interface: When a call to BeginEdit() is made on an already dirty instance, CancelEdit would then return the instance to the persistent state rather than the pre-BeginEdit() state.
I have found a solution which will work, but will also make unnecesary calls to the backend storage / business layer since a property will always be marked as dirty event if the original value is re-set. So my next question then is: Can you mark a property non-dirty. E.g.. IObjectContext.MakeNonDirty(String propertyName)? I'm completely happy using reflection for this...
Here is my IEditableObject implementation. A very crude implementation using reflection to create a snapshot of all read/write properties at BeginEdit() call:
public abstract class EditableObject : IEditableObject { |
/// <summary> |
/// The snapshot created when IEditableObject.BeginEdit is called. |
/// </summary> |
private Dictionary<PropertyInfo, object> m_IEditableObjectSnapshot; |
/// <summary> |
/// The cache of read/write properties to minimize reflection for IEditableObject. |
/// </summary> |
private List<PropertyInfo> m_ReadWriteProperties; |
/// <summary> |
/// Begins an edit on this instance. |
/// </summary> |
private void BeginEdit() { |
// Create new dictionary to hold current values of read/write properties |
m_IEditableObjectSnapshot = new Dictionary<PropertyInfo, Object>(); |
// Loop through all read/write properties in this |
foreach (PropertyInfo currentProperty in this.GetReadWriteProperties()) { |
// Get current value of current property |
Object currentValue = this.GetPropertyValue(currentProperty); |
// Add current value to dictionary using property as key |
m_IEditableObjectSnapshot.Add(currentProperty, currentValue); |
} |
} |
/// <summary> |
/// Discards changes since the last <see cref="IEditableObject.BeginEdit"/> |
/// was called. |
/// </summary> |
private void CancelEdit() { |
// Check if snapshot of property values exists |
if (m_IEditableObjectSnapshot != null) { |
// Create binding flags for property set invocation |
BindingFlags flags = BindingFlags.Instance | BindingFlags.SetProperty | BindingFlags.Public; |
// Loop through all PropertyInfo/Value pairs in dictionary |
foreach (var currentEntry in m_IEditableObjectSnapshot) { |
// Get name of current property |
String name = currentEntry.Key.Name; |
// Wrap original value in array |
Object[] value = new object[] { currentEntry.Value }; |
// Invoke property setter restoring original value |
this.GetType().InvokeMember(name, flags, null, this, value); |
} |
} |
// Reset property values snapshot |
m_IEditableObjectSnapshot = null; |
} |
/// <summary> |
/// Pushes changes since the last call to <see cref="IEditableObject.BeginEdit()"/> |
/// or <see cref="IBindingList.AddNew()"/> into this instance. |
/// </summary> |
private void EndEdit() { |
// Reset property values snapshot |
m_IEditableObjectSnapshot = null; |
} |
/// <summary> |
/// Gets the public properties of this instance which can be read and set externally. |
/// </summary> |
/// <returns>A list of public read/write properties.</returns> |
private List<PropertyInfo> GetReadWriteProperties() { |
// Check if RW properties are missing |
if (m_ReadWriteProperties == null) { |
// Create dictionary to hold read/write properties |
m_ReadWriteProperties = new List<PropertyInfo>(); |
// Loop through all public properties in this type |
foreach (PropertyInfo currentProperty in this.GetType().GetProperties()) { |
// Check if property is both read and write |
if ((currentProperty.CanRead) && (currentProperty.CanWrite)) { |
// Add current property to lisr |
m_ReadWriteProperties.Add(currentProperty); |
} |
} |
} |
// Return list of RW properties |
return m_ReadWriteProperties; |
} |
/// <summary> |
/// Gets the property value of the supplied property. |
/// </summary> |
/// <param name="property">The property.</param> |
/// <returns>The value of the property.</returns> |
private object GetPropertyValue(PropertyInfo property) { |
// Create binding flags for property get invocation |
BindingFlags flags = BindingFlags.Instance | |
BindingFlags.GetProperty | |
BindingFlags.FlattenHierarchy | |
BindingFlags.NonPublic | |
BindingFlags.Public; |
// Invoke property get on this and return value |
return this.GetType().InvokeMember(property.Name, flags, null, this, null); |
} |
} |
Thanks
Pål
0
Hi Pål,
Marking a property non dirty is only half of the code, you want to reset the value as well which leads possibly to a database turnaround as well.
I do not see a way to do this via reflection, it is far too complecated.
Sincerely yours,
Jan Blessenohl
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
Marking a property non dirty is only half of the code, you want to reset the value as well which leads possibly to a database turnaround as well.
I do not see a way to do this via reflection, it is far too complecated.
Sincerely yours,
Jan Blessenohl
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.