none
How to override DbContext ValidateEntity for parent entity RRS feed

  • Question

  • I am looking for ideas on how to override DbContext ValidateEntity to work with a parent / child entity situation. My parent entity is made up of 1 to many child entities. Validation at the parent level consists of summing the values of the child entities. In this case, the child entities represent allocations of 100%. Here is a code sample:

    Imports System.ComponentModel.DataAnnotations
    Imports System.Collections.Generic
    
    Public Class EmpDetailMaster
        Implements IValidatableObject
    
    #Region "properties"
        Public Property EmpID() As String
        Public Property ProductLines() As ICollection(Of ProductLineAlloc)
        Public Property Clients() As ICollection(Of ClientAlloc)
    #End Region
    
    
        Public Function Validate(validationContext As ValidationContext) As IEnumerable(Of ValidationResult) Implements IValidatableObject.Validate
            Dim results As List(Of ValidationResult) = New List(Of ValidationResult)
            If Clients.Sum(Function(x) x.Allocation) <> 100 Then
                Dim vr As New ValidationResult("Client allocation error - not equal to 100.", New String() {"Clients"})
                results.Add(vr)
            End If
            If ProductLines.Sum(Function(x) x.Allocation) <> 100 Then
                Dim vr As New ValidationResult("Product Line allocation error - not equal to 100.", New String() {"ProductLines"})
                results.Add(vr)
            End If
            Return results
        End Function
    End Class
    Public Class ProductLineAlloc
        Implements IValidatableObject
    
    #Region "properties"
        Public Property ProductLineAllocID() As Int32
        Public Property EmpID() As String
        Public Property ProductLineID() As Int32
        Public Property Allocation() As Int32
    #End Region
    
        Public Function Validate(validationContext As ValidationContext) As IEnumerable(Of ValidationResult) Implements IValidatableObject.Validate
            Dim results As List(Of ValidationResult) = New List(Of ValidationResult)
            If Allocation < 0 Or Allocation > 100 Then
                results.Add(New ValidationResult("ProductLine allocation must be between 0 and 100", New String() {"ProductLineAlloc"}))
            End If
            Return results
        End Function
    End Class
    
    Public Class ClientAlloc
        Implements IValidatableObject
    
    #Region "properties"
        Public Property ClientAllocID() As Int32
        Public Property EmpID() As String
        Public Property ClientID() As Int32
        Public Property Allocation() As Int32
    #End Region
    
    
        Public Function Validate(validationContext As ValidationContext) As IEnumerable(Of ValidationResult) Implements IValidatableObject.Validate
            Dim results As List(Of ValidationResult) = New List(Of ValidationResult)
            If Allocation < 0 Or Allocation > 100 Then
                results.Add(New ValidationResult("Client allocation must be between 0 and 100", New String() {"ClientAlloc"}))
            End If
            Return results
        End Function
    End Class
    
    
    

    This validation works fine but what I've discovered is that if I change a child entity the parent validation is not triggered by DbContext. ValidateEntity() will instead run validation for the child that was changed and never run for the parent so the values will never be checked to make sure they are 100.

    I did experiment with adding a property called Parent to each child so it could link back to the parent entity. Then I found the entity of that parent and set it's state to modified. This works if the state is modified but if a child is deleted then there is no parent and the state cannot be changed.

    The only solution I can think of is a brute force method where each parent entity is forced to be validated upon every call to ValidateEntity(). This would be hugely wasteful but I can't see how to make sure that changes to the child entities will force validation at the parent entity level.

     

    Tuesday, November 8, 2011 1:09 AM

Answers

  • So far the only possible solution I can see is what I have below and it is terrible. The issue I can resolve is deleted child entities. If a parent had 2 children which each hat 50% allocation, then the removal of one record should throw an error. However I can't find a way to force validation on that parent. Deleted records do not show in the ShouldValidateEntity(). I did consider looping through ChangeTracker.Entries where the deleted record does appear but I cannot link the child the parent because the primary ID is set to null on those deleted records (something I never read about in the documentation).

     

    Protected Overrides Function ShouldValidateEntity(entityEntry As System.Data.Entity.Infrastructure.DbEntityEntry) As Boolean
        If TypeOf entityEntry Is EmpDetailMaster Then
            Return True
        Else
            Return MyBase.ShouldValidateEntity(entityEntry)
        End If
    End Function
    

     

    • Marked as answer by pretzelb Friday, November 11, 2011 12:30 AM
    Tuesday, November 8, 2011 5:38 PM

All replies

  • So far the only possible solution I can see is what I have below and it is terrible. The issue I can resolve is deleted child entities. If a parent had 2 children which each hat 50% allocation, then the removal of one record should throw an error. However I can't find a way to force validation on that parent. Deleted records do not show in the ShouldValidateEntity(). I did consider looping through ChangeTracker.Entries where the deleted record does appear but I cannot link the child the parent because the primary ID is set to null on those deleted records (something I never read about in the documentation).

     

    Protected Overrides Function ShouldValidateEntity(entityEntry As System.Data.Entity.Infrastructure.DbEntityEntry) As Boolean
        If TypeOf entityEntry Is EmpDetailMaster Then
            Return True
        Else
            Return MyBase.ShouldValidateEntity(entityEntry)
        End If
    End Function
    

     

    • Marked as answer by pretzelb Friday, November 11, 2011 12:30 AM
    Tuesday, November 8, 2011 5:38 PM
  • Hi pretzelb,

    Thanks for sharing your experience here.

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, November 9, 2011 8:13 AM
    Moderator
  • If no one else can think of an alternative idea I will mark my response as the answer after a day or so.
    Wednesday, November 9, 2011 11:30 PM