I have a parent object that depending on some business logic should create a child.
public class ParentClass : BusinessBase<ParentClass>
{
private readonly static PropertyInfo<int> SomeIdProperty = RegisterProperty<int>(prop => prop.SomeId, "Some Id);
public int SomeId
{
get { return GetProperty(SomeIdProperty); }
set { SetProperty(SomeIdProperty, value); }
}
private readonly static PropertyInfo<ChildClass> ChildObjectProperty = RegisterProperty<ChildClass>(prop => prop.Child, "Child Object");
public ChildClass Child
{
get
{
if (!FieldManager.FieldExists(ChildObjectProperty))
{
LoadProeprty(ChildObjectProperty, DataPortal.CreateChild<ChildClass>());
}
return GetProperty(ChildObjectProperty);
}
set { SetProperty(ChildObjectProperty, value); }
}
// factory methods
protected override void AddBusinessRules()
{
BusinessRules.AddRule(new ChildCreateRule(SomeIdProperty, ChildObjectProperty));
}
private class ChildCreateRule : Csla.Rules.BusinessRule
{
public ChildCreateRule(PropertyInfo PrimaryProperty, PropertyInfo ChildProperty)
: base(PrimaryProperty)
{
InputProperties.Add(PrimaryProperty);
InputProperties.Add(ChildProperty);
}
protected override void Execute(Csla.Rules.RuleContext context)
{
base.Execute(context);
int id = (dynamic)context.InputPropertyValues[InputProperties[0]];
if(id > SomeNumberCriteria)
{
ChildClass kid = ChildClass.NewChildClass();
IPropertyInfo childInfo = InputProperties[1];
context.AddOutValue(childInfo, kid);
}
}
}
// dataportal methods
}
Is this a good approach? Should biz rules have this kind of behavior, the reason I went down this road is b/c there are cases when I may(or may not) want a child object. It depends on the value of SomeId.
If this is not a good approach, can you suggest a better one?
It's those "AffectedProperties" that got me again. If any needs the answer, something like:
private class ChildCreateRule
{
public ChildCreateRule(PropertyInfo PrimaryProperty, PropertyInfo ChildProperty)
: base(PrimaryProperty)
{
InputProperties.Add(PrimaryProperty);
AffectedProperties.Add(ChildProperty);
}
protected override void Execute(Csla.Rules.RuleContext context)
{
base.Execute(context);
int id = (dynamic)context.InputPropertyValues[PrimaryProperty];
if(id > SomeNumber)
{
ChildClass kid = ChildClass.NewChildClass();
IPropertyInfo childInfo = AffectedProperties[0];
context.AddOutValue(childInfo, kid);
}
}
}
Hi,
I do not recommend to use a business rule delete/create child objects.
I'd rather look at using authorization rules or overloads of Can<XYZ> to "hide" the child object/property values when they should not be available (readable/editable) and shortcircuit the validation rules when user is not allowed to edit fields.
I agree with JonnyBee, and that's what we've done in our apps with CanAddBusinessCase, CanDelete_xxxx methods as an example, etc, as we can use these not only to check if user is in correct role, but also look at our custom permissions model and of course execute lookups against our database and/or query other business objects.
The logic to determine if a child object gets created isn't tied to authorization, it's more like "if (SomePropertyId == 5) CreateChild". The basic design is when the parent object is saved to the database, if a property is set to a particular value, then create the child and insert into the db with the parent. There would be no UI piece or any way for the user to interact with it(this is by design).
If you have access/authorization to the root object, then you have access/authorization to create/save the child object.
Hi,
Then it seems to me that this is Save-logic (that belongs in the Data Access Layer) and not a business rule in the Business Object.
That was my original thought, but then I moved it to a business rule. I'll be moving it back in the DA layer.
Copyright (c) Marimer LLC