I have a biz object that has a business rule that requires one of the two properties to be set, but not both has to be set. The rule works fine when one of the options is set and then saved. The problems arise when a user might want to reassign work from a user to a group(or vice versa). In code I set the old to null, and sets the other to the appropriate id. Below is an example:
Which versjon of CSLA?
Your existing code would run as expected with CSLA 4.2 as the Rule engine considers InputProperties as Dependency.
In CSLA 4.1/4.0 only AffectedProperties is used for Dependency so your rule must add secondaryProperty to AffectedProperties.
This code and tests runs OK for CSLA 4.1:
[Serializable] public partial class Work : BusinessBase<Work> { private static readonly PropertyInfo<System.Int32> IdProperty = RegisterProperty<System.Int32>(p => p.Id, "Work Id"); public System.Int32 Id { get { return GetProperty(IdProperty); } set { SetProperty(IdProperty, value); } } 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); } } private static readonly PropertyInfo<System.Int32?> GroupIdAssignToProperty = RegisterProperty<System.Int32?>(p => p.GroupIdAssignTo, "Group Id Assign To"); public System.Int32? GroupIdAssignTo { get { return GetProperty(GroupIdAssignToProperty); } set { SetProperty(GroupIdAssignToProperty, value); } } protected override void AddBusinessRules() { base.AddBusinessRules(); BusinessRules.AddRule(new AssignWork(UserIdAssignToProperty, GroupIdAssignToProperty)); BusinessRules.AddRule(new AssignWork(GroupIdAssignToProperty, UserIdAssignToProperty)); } } internal class AssignWork : BusinessRule { public IPropertyInfo SecondaryProperty { get; set; } public AssignWork(IPropertyInfo primaryProperty, IPropertyInfo secondaryProperty) : base(primaryProperty) { SecondaryProperty = secondaryProperty; if (InputProperties == null) InputProperties = new List<IPropertyInfo>(); InputProperties.Add(primaryProperty); InputProperties.Add(secondaryProperty); AffectedProperties.Add(secondaryProperty); } protected override void Execute(Csla.Rules.RuleContext context) { var value1 = (dynamic) context.InputPropertyValues[PrimaryProperty]; var value2 = (dynamic) context.InputPropertyValues[SecondaryProperty]; if (value1 == null && value2 == null) { context.AddErrorResult(String.Format("Either assign to {0} or {1}", PrimaryProperty.FriendlyName, SecondaryProperty.FriendlyName)); } else if (value1 != null && value2 != null) { context.AddErrorResult(String.Format("Can not assign both {0} and {1}", PrimaryProperty.FriendlyName, SecondaryProperty.FriendlyName)); } } } [TestClass] public class TestWork { [TestMethod] public void Test1() { Work myWork = new Work(); myWork.UserIdAssignTo = 123; Assert.IsTrue(myWork.IsValid); myWork.UserIdAssignTo = null; // Object is in an invalid state here Assert.IsFalse(myWork.IsValid); myWork.GroupIdAssignTo = 456; // Object *should* no longer be in an invalid state, all rules satisfied Assert.IsTrue(myWork.IsValid); Assert.IsTrue(myWork.IsSavable); } [TestMethod] public void Test2() { Work myWork = new Work(); myWork.GroupIdAssignTo = 456; Assert.IsTrue(myWork.IsValid); myWork.GroupIdAssignTo = null; // Object is in an invalid state here Assert.IsFalse(myWork.IsValid); myWork.UserIdAssignTo = 123; // Object *should* no longer be in an invalid state, all rules satisfied Assert.IsTrue(myWork.IsValid); Assert.IsTrue(myWork.IsSavable); } }
Thanks again JohnnyBee, I upgraded to 4.2.2 and it works.
Copyright (c) Marimer LLC