IN SHORT: I am trying to
make sure that for a given value on a child object conforms to a value on a
parent object using CSLA 2.1.4 validation framework.
GORY DETAILS
Allocation objects have a field
"ProductLine".
AllocationDetail
objects have a field "Part".
I would like CSLA to validate that each AllocationDetail.Part chosen also belongs to it's Allocation.ProductLine.
I have a lookup table in memory of type List<Part> that I build for a
given Allocation.ProductLine.
One more thing... the Allocation object is not supposed to allow edits
(which I accomplished only using SETTERS), but it has a RemainingAllocation
field that should get updated from all the child objects... I’m trying to use
this as a trigger…
What I'm currently doing is this:
[Serializable]
public class Allocation :
BusinessBase<Allocation>
{
//snip
private AllocationDetailList detailList;
//snip
protected
override void AddBusinessRules()
{
base.AddBusinessRules();
ValidationRules.AddInstanceRule<Allocation>(AllocationDetailsEqualAllocationAmount, "RemainingAllocation");
ValidationRules.AddInstanceRule<Allocation>(PartsBelongsToPL, "RemainingAllocation");
}
//snip
private
bool PartsBelongsToPL(Allocation target,
RuleArgs e)
{
bool
foundPart = detailList.CheckPartsForPL(target);
if (foundPart)
{
e.Description = "Parts in the allocation do not belong to the
originating Product Line.";
e.Severity = RuleSeverity.Error;
return
false;
}
else
{
e.Description = string.Empty;
return
true;
}
}
//snip
void detailList_ListChanged(object
sender, ListChangedEventArgs
e)
{
//Recalculate
RemainingAmount and fire a REFRESH up the STACK!
PropertyHasChanged("RemainingAllocation");
}
//snip
}
[Serializable]
public class AllocationDetailList
: BusinessListBase<AllocationDetailList, AllocationDetail>
{
//snip
internal
bool CheckPartsForPL(Allocation allocation)
{
RaiseListChangedEvents
= false;
List<Part> list = Lookups.PartsForProductLine(allocation.ProductLine);
bool
foundPart = false;
foreach
(AllocationDetail detail
in this)
{
foreach
(Part pTest
in list)
{
if
(pTest.ID
== detail.PartID)
{
foundPart = true;
break;
}
}
detail.SetBelongsToParentProductLine(foundPart);
}
RaiseListChangedEvents
= true;
return
foundPart;
}
//snip
}
public class AllocationDetail
: BusinessBase<AllocationDetail>
{
//snip
private
bool belongsToParentProductLine
= true;
//snip
public void SetBelongsToParentProductLine(bool value)
{
belongsToParentProductLine
= value;
PropertyHasChanged("PartName");
}
//snip
protected
override void AddBusinessRules()
{
base.AddBusinessRules();
//snip
ValidationRules.AddInstanceRule<AllocationDetail>(CheckBelongsToParentPL, "PartName");
}
//snip
private
bool CheckBelongsToParentPL(AllocationDetail target,
RuleArgs e)
{
if
(target.BelongsToParentProductLine
== false)
{
e.Description = "Part does not belong to main Product Line,
please adjust the Part to match the original Product Line.";
e.Severity = RuleSeverity.Error;
return
false;
}
else
return
true;
}
//snip
}
Obviously this isn’t working
properly, but I cannot see why… My gut tells me I’m doing something the “hard
way”.
I am using:
Child objects in a list have a Parent property that you can use to get at the list object.
You can implement a Parent property in your list, if it is contained by some other object. You need to set that Parent property when the list is created, and in the OnDeserialized() override. Also, make sure it is marked as NonSerialized and NotUndoable.
But once you have the Parent properties all set up, you should be able to implement a rule method that would go up the object graph to find whatever parent information you need to do the validation.
Copyright (c) Marimer LLC