Validating Child Value based on Parent's Value

Validating Child Value based on Parent's Value

Old forum URL: forums.lhotka.net/forums/t/3573.aspx


BVeenstra posted on Thursday, September 20, 2007

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

 Here’s the object graph:

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:


Thanks for any comments, large or small!

RockfordLhotka replied on Monday, September 24, 2007

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