I have a biz object where I need to check that Work has been assigned to either a person(UserId) or a group of people(Group), but not both. I'm having problems when I try to assign a user(using test cases to test my work). Below is my code(some parts snipped out for clarity).
[Serializable]
public partial class Work : BusinessBase<Work>
{
private static readonly PropertyInfo<System.Int32?> UserIdAssignToProperty = RegisterProperty<System.Int32?>(p => p.UserIdAssignTo, "User Id Assign To");
public System.Int32? UserIdAssignTo
{
get { return GetProperty(UserIdAssignToProperty); }
set { SetProperty(UserIdAssignToProperty, value); } // error is happening here
}
private static readonly PropertyInfo<Group> GroupProperty = RegisterProperty<Group>(p => p.GroupAssignTo, "Group Assign To", Csla.RelationshipTypes.LazyLoad);
public Group GroupAssignTo
{
get
{
bool cancel = false;
OnChildLoading(GroupProperty, ref cancel);
if (!cancel)
{
if(!FieldManager.FieldExists(GroupProperty))
{
LoadProperty(GroupProperty, Group.GetByWorkChild(this));
}
}
return GetProperty(GroupProperty);
}
protected set { SetProperty(GroupProperty, value); }
}
protected override void AddBusinessRules()
{
base.AddBusinessRules();
BusinessRules.AddRule(new AssignWork(UserIdAssignToProperty, GroupProperty));
BusinessRules.AddRule(new AssignWork(GroupProperty, UserIdAssignToProperty));
BusinessRules.AddRule(new AnotherBizRule(UserIdAssignToProperty));
}
// parent factory methods
// parent data portal
}
[Serializable]
public partial class Group : BusinessBase<Group>
{
private static readonly PropertyInfo<System.Int32?> IdProperty = RegisterProperty<System.Int32?>(p => p.Id, "Group Id");
public System.Int32? Id
{
get { return GetProperty(IdProperty); }
set { SetProperty(IdProperty, value); }
}
private static readonly PropertyInfo<System.String> NameProperty = RegisterProperty<System.String>(p => p.Name, "Group Name");
public System.String Name
{
get { return GetProperty(NameProperty); }
set { SetProperty(NameProperty, value); }
}
// child factory methods
// child data portal methods
}
internal class AssignWork : BusinessRule
{
public AssignWork(IPropertyInfo PrimaryProperty, IPropertyInfo SecondaryProperty)
: base(PrimaryProperty)
{
if (InputProperties == null)
{
InputProperties = new List<IPropertyInfo>();
}
InputProperties.Add(PrimaryProperty);
InputProperties.Add(SecondaryProperty);
}
protected override void Execute(Csla.Rules.RuleContext context)
{
base.Execute(context);
IPropertyInfo groupProp = InputProperties.Find(prop => prop.FriendlyName.Equals("Group Assign To"));
IPropertyInfo userProp = InputProperties.Find(prop => prop.FriendlyName.Equals("User Id Assign To"));
var userId = (dynamic)context.InputPropertyValues[userProp];
var group = (dynamic)context.InputPropertyValues[groupProp];
if (userId != null && (group != null && group.Id == null))
{
context.AddErrorResult(String.Format("Either assign to {0} or {1}, not both", userProp.FriendlyName, groupProp.FriendlyName));
}
}
}
internal class AnotherBizRule : BusinessRule
{
public AnotherBizRule(IPropertyInfo PrimaryProperty, IPropertyInfo SecondaryProp)
: base(PrimaryProperty)
{
if (InputProperties == null)
{
InputProperties = new List<IPropertyInfo>();
}
InputProperties.Add(PrimaryProperty);
}
protected override void Execute(Csla.Rules.RuleContext context)
{
base.Execute(context);
// do some biz rule on the UserId property, it works in this rule
}
}
// Unit Test Case (mbUnit)
[Test]
public void Test1()
{
Work myWork = Work.NewWork();
myWork.UserIdAssignTo = 123; // errors here
myWork.Group = SomeGroup;
// check BrokenRulesCollection to see if I caught the broken rule(s)
}
[Test]
public void Test2()
{
Work myWork = Work.NewWork();
myWork.Group = SomeGroup;
myWork.UserIdAssignTo = 123;
// check BrokenRulesCollection to see if I caught the broken rule(s)
}
Any help/suggestions would be greatly appreciated.
Forgot to include the error I was getting:
Error from Vis. Studio:
Property load or set failed for property UserIdAssignTo (Property get not allowed)
Inner Exception: {"Property get not allowed"}
Stack Trace:
at Csla.Core.BusinessBase.ReadProperty(IPropertyInfo propertyInfo)
at Csla.Core.BusinessBase.Csla.Core.IManageProperties.ReadProperty(IPropertyInfo propertyInfo)
at Csla.Rules.BusinessRules.RunRules(IEnumerable`1 rules)
at Csla.Rules.BusinessRules.CheckRulesForProperty(IPropertyInfo property, Boolean cascade)
at Csla.Rules.BusinessRules.CheckRules(IPropertyInfo property)
at Csla.Core.BusinessBase.PropertyHasChanged(IPropertyInfo property)
at Csla.Core.BusinessBase.LoadPropertyValue[P](PropertyInfo`1 propertyInfo, P oldValue, P newValue, Boolean markDirty)
at Csla.Core.BusinessBase.SetProperty[P](PropertyInfo`1 propertyInfo, P newValue, NoAccessBehavior noAccess)
The error is connected with Lazy loading of fields.
When your rule is using a lazy loaded field you must create the rule as an inner rule inside your BO so the rule can have access to FieldDataManager and check if the value is created or not. You cannot use the InputProperties to specify the lazy field as an input to the rule.
As a side note:
I am curios about the relationship between Work and Group. Is it a
This is described in the UsingCsla4-02-Objects ebook from Rocky and have slightly different property declaration syntax.
From what I can see from your code - I'd rather have GroupId and GroupName as properties of the Work object rather than having an owning lazy loaded Group object. (and a rule that will lookup and set GroupName asyncronously when GroupId is set).
Thanks for your help JonnyBee, I originally had Group as GroupId, but figured I'd make "Group" a child object to the Parent "Work". I went ahead and switched back to a GroupId(I really don't need the GroupName to persist to the db).
I think I need to go back and reread the Csla4-02 Objects book, my understanding may not be where it needs to be...
Copyright (c) Marimer LLC