Hello community!
I'm lost with the undo capabilities of CSLA. I have found several questions/answers dealing with the strange behavior of data binding under windows forms.
But alas, I'm not using data binding at all in my test application. I'm using CSLA 3.8.4, C#, .NET 3.5SP1, VS2010, NHibernate with Fluent-NHibernate.
I have built the following business objects:
User object with 4 properties: UserID, FirstName, LastName and Role
UserRole object with 2 properties: ID and Description.
So far so good, I am able to persist these objects in the SQLite-DB.
Then I reload one user object from the DB, call .BeginEdit on it and assign another UserRole to the Role property ...
Afterwards I call .CancelEdit, expecting my user object's role property would revert to it's state before the .BeginEdit call ...
But that's not the case
What am I doing wrong ?
Seasons greetings
Philippe
As I've spent almost 2 days on this issue, I thought I may be lost in my code … so I reverted back to a simple test …
But even this doesn't work to my expectations … the MyChild property doesn't revert back to 'InitialChild' after the call to root.CancelEdit …
[Serializable]
public class Root : BusinessBase<Root>
{
private static PropertyInfo<int> IdProperty = RegisterProperty<int>(typeof(Root), new PropertyInfo<int>("Id", "Id"));
public int Id
{
get { return GetProperty<int>(IdProperty); }
set { SetProperty<int>(IdProperty, value); }
}
private static PropertyInfo<string> NameProperty = RegisterProperty<string>(typeof(Root), new PropertyInfo<string>("Name", "Name"));
public string Name
{
get { return GetProperty<string>(NameProperty); }
set { SetProperty<string>(NameProperty, value); }
}
private static PropertyInfo<Child> ChildProperty = RegisterProperty<Child>(typeof(Root), new PropertyInfo<Child>("Children", "Children"));
public Child MyChild
{
get
{
if (!FieldManager.FieldExists(ChildProperty))
LoadProperty<Child>(ChildProperty, new Child());
return GetProperty<Child>(ChildProperty);
}
set { SetProperty(ChildProperty, value); }
}
protected override object GetIdValue()
{
return ReadProperty<int>(IdProperty);
}
}
[Serializable]
public class Child : BusinessBase<Child>
{
private static PropertyInfo<int> IdProperty = RegisterProperty<int>(typeof(Child), new PropertyInfo<int>("Id", "Id"));
public int Id
{
get { return GetProperty<int>(IdProperty); }
set { SetProperty<int>(IdProperty, value); }
}
private static PropertyInfo<string> NameProperty = RegisterProperty<string>(typeof(Child), new PropertyInfo<string>("Name", "Name"));
public string Name
{
get { return GetProperty<string>(NameProperty); }
set { SetProperty<string>(NameProperty, value); }
}
protected override object GetIdValue()
{
return ReadProperty<int>(IdProperty);
}
private static int _lastId;
public Child()
{
LoadProperty<int>(IdProperty, System.Threading.Interlocked.Increment(ref _lastId));
MarkAsChild();
}
}
class Program
{
static void Main(string[] args)
{
var root = new Root {Id = 1, Name = "TestRoot"};
root.MyChild = new Child() { Name = "InitialChild" };
root.BeginEdit();
root.MyChild = new Child(){Name = "TestChild"};
root.CancelEdit();
}
}
The problem here is that you cannot change the object references.
You may change the properties of parent and child - and add/remove items in lists but you cannot change the object intance. The undo mechanism just will not be able to handle this properly.
Takk JonnyBee
With your suggestion the undo works as I want it to work. But I've got another problem…
The foreign key from the root to the child object in the DB doesn't get updated afterwards I assign new values to the child's properties.
Philippe
Hi,
Is that after Save is called or when you assign values to the child's properties?
Can you show some code sample?
Hi
this is what I'm trying to do:
static void Main(string[] args)
{
var userRoles = UserRoles.NewList();
var roleOne = UserRole.NewRole();
roleOne.Name = "RoleOne";
roleOne.IsActive = false;
var roleTwo = UserRole.NewRole();
roleTwo.Name = "RoleTwo";
roleTwo.IsActive = true;
userRoles.Add(roleOne);
userRoles.Add(roleTwo);
userRoles.Save();
//
var testUser = User.NewUser();
testUser.FirstName = "User";
testUser.LastName = "Test";
testUser.UserID = "testUser";
testUser.Role = UserRole.GetByID(1);
testUser = testUser.Save();
// change role assigned to user
var testUser2 = User.GetByID(1);
testUser2.Role = UserRole.GetByID(2);
testUser2 = testUser2.Save();
}
After 'testUser2.Save()' my user's record in the DB has the correct foreign key. The FK points now to role# 2.
Now let's imagine that there is some UI to modify the assignement of the user role. And this is where I can't have the undo function.
…
var testUser2 = User.GetByID(1);
testUser2.BeginEdit();
testUser2.Role = UserRole.GetByID(2); // simulate an assignement from the UI
testUser2.CancelEdit();
…
This doesn't work.
I suspect that I'm better off to fetch the record being edited again when a user wants to undo his modifications, don't I ?
Philippe
[Serializable]
public class User : NHibernateBusinessBase<User>
{
#region Business Methods
private int _iD;
private static readonly PropertyInfo<int> IDProperty = RegisterProperty<int>(p => p.ID);
public virtual int ID
{
get { return GetProperty(IDProperty, _iD); }
set { SetProperty(IDProperty, ref _iD, value); }
}
private string _userID;
private static readonly PropertyInfo<string> UserIDProperty = RegisterProperty<string>(p => p.UserID, "User ID");
public virtual string UserID
{
get { return GetProperty(UserIDProperty, _userID); }
set { SetProperty(UserIDProperty, ref _userID, value); }
}
private string _firstName;
private static readonly PropertyInfo<string> FirstNameProperty = RegisterProperty<string>(p => p.FirstName, "First name");
public virtual string FirstName
{
get { return GetProperty(FirstNameProperty, _firstName); }
set { SetProperty(FirstNameProperty, ref _firstName, value); }
}
private string _lastName;
private static readonly PropertyInfo<string> LastNameProperty = RegisterProperty<string>(p => p.LastName, "Last name");
public virtual string LastName
{
get { return GetProperty(LastNameProperty, _lastName); }
set { SetProperty(LastNameProperty, ref _lastName, value); }
}
private UserRole _role;
private static readonly PropertyInfo<UserRole> UserRoleProperty = RegisterProperty<UserRole>(p => p.Role,
"User role",
UserRole.NewRole(),
RelationshipTypes.
Child);
public virtual UserRole Role
{
get { return GetProperty(UserRoleProperty, _role); }
set { SetProperty(UserRoleProperty, ref _role, value); }
}
#endregion
#region Business Rules
protected override void AddBusinessRules()
{
ValidationRules.AddRule(CommonRules.StringRequired, new RuleArgs(UserIDProperty));
ValidationRules.AddRule(CommonRules.StringRequired, new RuleArgs(FirstNameProperty));
ValidationRules.AddRule(CommonRules.StringRequired, new RuleArgs(LastNameProperty));
}
#endregion
#region Authorization Rules
#endregion
#region Factory Methods
protected User()
{
}
public static User GetByID(int id)
{
return DataPortal.Fetch<User>(new SingleCriteria<User, int>(id));
}
public static User NewUser()
{
return DataPortal.Create<User>();
}
#endregion
#region Data Access
#endregion
#region Overrides
public override string ToString()
{
return string.Format("{0} {1}", FirstName, LastName);
}
protected override object GetUniqueIdentifier(object businessCriteria)
{
return ((SingleCriteria<User, int>)businessCriteria).Value;
}
#endregion
}
[Serializable]
public class UserRole : NHibernateBusinessBase<UserRole>
{
#region Business Methods
private int _iD;
private static readonly PropertyInfo<int> IDProperty = RegisterProperty<int>(p => p.ID);
public virtual int ID
{
get { return GetProperty(IDProperty, _iD); }
set { SetProperty(IDProperty, ref _iD, value); }
}
private string _name;
private static readonly PropertyInfo<string> NameProperty = RegisterProperty<string>(p => p.Name, "Role name", String.Empty);
public virtual string Name
{
get { return GetProperty(NameProperty, _name); }
set { SetProperty(NameProperty, ref _name, value); }
}
private bool _isActive;
private static readonly PropertyInfo<bool> IsActiveProperty = RegisterProperty<bool>(p => p.IsActive, "State", false);
public virtual bool IsActive
{
get { return GetProperty(IsActiveProperty, _isActive); }
set { SetProperty(IsActiveProperty, ref _isActive, value); }
}
#endregion
#region Business Rules
protected override void AddBusinessRules()
{
ValidationRules.AddRule(CommonRules.StringRequired, NameProperty, 0);
}
#endregion
#region Authorization Rules
#endregion
#region Factory Methods
public static UserRole GetByID(int temp)
{
return DataPortal.Fetch<UserRole>(new SingleCriteria<UserRole, int>(temp));
}
public static UserRole NewRole()
{
return DataPortal.CreateChild<UserRole>();
}
protected UserRole()
{
}
#endregion
#region Data Access
#endregion
#region Overrides
public override string ToString()
{
return Name;
}
protected internal override void Init()
{
base.Init();
MarkAsChild();
}
protected override object GetUniqueIdentifier(object businessCriteria)
{
return ((SingleCriteria<UserRole, int>)businessCriteria).Value;
}
#endregion
}
Copyright (c) Marimer LLC