Validation Rules With Parent Child Relationships. Is it a Bug?

Validation Rules With Parent Child Relationships. Is it a Bug?

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


jlfernandezmiranda posted on Wednesday, March 03, 2010

Hi guys.

I use CSLA 3.7 version

I have a Editable Root named Root1 and 2 EditableChilds:  Child1 and Child2

Child1 and Child2 are sharing the same string property( named Shared_Child_Property)

I want to validate if exist at least one value not nullorempty for Shared_Child_Property  (it is the same if exist in Child1.SharedProperty or Child2.SharedProperty)

in root 1 i declared:

Private Shared Child1Property As PropertyInfo(Of Child1) = _
RegisterProperty(New PropertyInfo(Of Child1)("Child"))
Public ReadOnly Property Child1() As Child1
Get
If Not FieldManager.FieldExists(Child1) Then
LoadProperty(Child1Property, Child1.NewChild())
End If
Return GetProperty(Child1Property)
End Get
End Property

....

The same property declaration i did for Child2

My problem is the follow:

In Child_Create method of Child1, i call ValidationRules(the same ocurrs for child2)...

And ValidationRules in Child 1 call this function :

 Private Function ValidateAtLeastOneSharedProperty(Of T As Root1)( _
                         ByVal target As T, ByVal e As RuleArgs) As Boolean

dim parent as Root1 = target.GetParent

dim IsValidSharedPropChild1 as boolean = not string.IsnullorEmpty(target.Shared_Child_Property)

dim IsValidSharedPropChild2 as boolean = not string.IsnullorEmpty(parent.Child2.Shared_Child_Property)

if not IsValidSharedPropChild1 andAlso not IsValidSharedPropChild2 then

e.Description = "You must enter at least one valid string for Shared_Child_Property"

return false

else

return true

end if

End Function

 

I don´t know why target.GetParent return 'nothing' in the first call( when -i call from Child_Create), but if i write any string on child1.Shared_Child_Property and then delete the error provider worksfine, because return a correct parent (root1) instead of return 'nothing'.

 Any Ideas. Thanks Jose Luis

 

 

 

 

 

RockfordLhotka replied on Wednesday, March 03, 2010

The Parent property isn't set until the child object is actually added as a child of the parent.

Creating the child object occurs first. Then the child is added as a child of the parent.

The DataPortal_Create() method is what is creating the child. This occurs before the object is assigned to its parent.

jlfernandezmiranda replied on Thursday, March 04, 2010

Thanks Rocky.

I read your book and I would need to catch FieldDataDeserialized() method in root1 to call validationrules.checkrules.

But I solved this problem calling ValidationRules.CheckRules from  DataPortal_OnDataPortalInvokeComplete, in this method I check

If ApplicationContext.ExecutionLocation = _
              ApplicationContext.ExecutionLocations.Client AndAlso _
              e.Operation = (DataPortalOperations.Create) Then

 

'''''''''''''''EnforceValidationRulesOn Child1 and Child2 Shared_Property'''''''''''

Child1.EnforceValidationManually

Child2.EnforceValidationManually

end if

Because this 2 rules are dependants, but theirs locations are in distincts childproperties,

I had to add this lines in Set Block of each Shared_Property.

For Shared_Property in child1 I do:

        Set(ByVal value As String)
                SetProperty(Of String)( Shared_Property, value.Trim)

                Dim parent As Object = TryCast(Me.Parent, root1)
                If parent IsNot Nothing Then
                    CType(parent, root).Child2.EnforceValidationManually
                End If

            End Set

             
This line call the ValidationRule for  child2.SharedProperty, but NOT REMOVE the broken rule because Property_Changed has not been fired.

Is there any way easier to do this?

If I have 2 dependant properties to validate in 2 diferents editablechild properties, how do i to create a ruleDependant?

 

Thanks

 

 

 

 

 

RockfordLhotka replied on Friday, March 05, 2010

I typically put this kind of rule in the parent object, not in the child. The parent object knows when the child object is created, and when it changes, so it is a simple location to put this type of rule.

jlfernandezmiranda replied on Friday, March 05, 2010

Hi Rocky, thanks for your answer

I have a Root: ---> CustomerA

             And 2 Childs  -----> HomePhone

                                                                        ------------------> These childs props are sharing PhoneNumerProperty(String)

                                     ------->WorkPhone

I choose this implementation because i don't want to save null values in my database.

I put the rule in the parent like you suggest me, in this way:

This is my code:

    <Serializable()> _
    Public Class CustomerA
        Inherits BusinessBase(Of CustomerA)

.........

'''''''  this is Child1

    Private Shared HomePhoneProperty As PropertyInfo(Of  HomePhone) = RegisterProperty(New PropertyInfo(Of  HomePhone)("HomePhone", "HomePhone"))
        ''' <Summary>
        ''' Gets the HomePhone value.
        ''' </Summary>
        Public ReadOnly Property HomePhone() As HomePhone
            Get
                If Not FieldManager.FieldExists(HomePhoneProperty) Then
                     LoadProperty(Of HomePhone)(HomePhoneProperty, HomePhone.NewHomePhone)
                End If
                Return GetProperty(HomePhoneProperty)
            End Get
        End Property


'''''''  this is Child2

    Private Shared WorkPhoneProperty As PropertyInfo(Of WorkPhone) = RegisterProperty(New PropertyInfo(Of WorkPhone)("WorkPhone", "WorkPhone"))
        ''' <Summary>
        ''' Gets the WorkPhone value.
        ''' </Summary>
        Public ReadOnly Property WorkPhone() As WorkPhone
            Get
                If Not FieldManager.FieldExists(WorkPhoneProperty) Then
                     LoadProperty(Of WorkPhone)(WorkPhoneProperty, WorkPhone.NewWorkPhone)
                End If
                Return GetProperty(WorkPhoneProperty)
            End Get
        End Property

........

        Protected Overrides Sub AddBusinessRules()

                      ValidationRules.AddRule(Of CustomerA)(AddressOf ValidateAtLeat1Phone(Of CustomerA), HomePhoneProperty, 3)
                      ValidationRules.AddRule(Of CustomerA)(AddressOf  ValidateAtLeat1Phone(Of CustomerA),WorkPhoneProperty, 3)

                      ValidationRules.AddDependentProperty(HomePhoneProperty, WorkPhoneProperty, True)

 

        End Sub

 

  Private Shared Function ValidateAtLeat1Phone(Of T As CustomerA)( _
      ByVal target As T, _
      ByVal e As Validation.RuleArgs) As Boolean


     dim hasHomePhone as boolean= not String.IsNullOrEmpty(target.HomePhone.PhoneNumer)

     dim hasWorkPhone as boolean= not String.IsNullOrEmpty(target.WorkPhone.PhoneNumer)

     dim IsValidRule as boolean =  not hasHomePhone AndAlso hasWorkPhone)

      if not IsValidRule then

        e.Description= "You must enter 1 phone number"

    end if

       Return  IsValidRule

        End Function

   End Class

When I create the root, the ValidateAtLeat1Phone is called but the errorprovider no catch it , so the description of broken rule is not shown, and also the   function is not fired when I change  PhoneNumerProperty in a child.

What is my mistake?

How do i to fire this ruleMethod?

THANKS YOU VERY MUCH

 

jlfernandezmiranda replied on Monday, March 08, 2010

Rocky, my first question when I design this Validation Rule was the following:

What is the OBJECT that handles the rule behavior?

My answer was: The object is the shared property(PhoneNumber) located in child property, so it is a good place to put the validation rule. The parent object(root object) has no responsability to handle this shared property, so to put the validation rule in this class is no sense.

In my UI i have 3 errorprovider controls, 1 for root and the others 2 for childs and also each error provider handles your own datasource (child class) so the root error provider  has no responsability to manage the child property, because of this the rule broken is not shown. I could catch the root error provider in Property child events of root object in the UI and set error in the root error provider, but this idea violates encapsulation and normalization of behavior.

 

 

Copyright (c) Marimer LLC