Hi,
My webapplication gives the user the possibility to change a lot of things about a Store,for instance openinghours and openinghours exception(a store will have openinghours 10-20 each day but on may 1st it is open only 10-14). Where do I implement a validationrule for unique dates, that is only one openinghoursexception on may 1st. My users wants this errormessage when they save the store not when adding the exception as it will require a postback.
There is no brokenrulescollection for lists, so I cant implement this rule in the list. I could add this rule to the Store object (having an OpeningHoursExceptionList) but the rule doesnt only apply to stores, it applies to every thing having openinghours exceptions. And sometimes this list is not "owned" by any parent, as it is possible to create a template list of openinghours exceptions to be used for new stores.
I have several other types of list with list specific validation. I have a list of concepts where the names of the concepts must be unique.Other examples of rules are that only three of the same types of store in the same area e.t.c.
Anyone have any suggestions? Why doesnt the lists have a brokenrulescollection and why cant u add businessrule to them?
It is impossible to create your own implementation of Brokenrulescollection as you cant inherit it (sealed) and not instatiate it(internal constructor)
rosjon:It is impossible to create your own implementation of Brokenrulescollection as you cant inherit it (sealed) and not instantiate it(internal constructor)
Check out the CslaContrib project. (Links are on the forum home page).
Download the CslaContrib code, and Look for the CslaSrd project inside of it.
If they don't do what you want, you might still pick up some useful background info.
Classes of interest:
RuleBusinessBase -> subclasses BusinessBase, includes a BrokenRules and Rules property.
RuleBusinessListBase -> subclasses BusinessListBase
PublicRuleInfo and PublicRuleInfoList (a collection of all rules)
Resources File (rule error messages rewritten slightly so PublicRuleInfo can display them.)
StdRules -> a clone of CommonRules where the rules use the new Resources file error strings.
============
other classes of interest, but off this topic, are SmartInt16, SmartInt32, SmartInt64, SmartFloat, SmartDecimal and SmartBool, plus SmartSafeDataReader (which adds support for the new smart classes.)
rosjon:Anyone have any suggestions? Why doesnt the lists have a brokenrulescollection and why cant u add businessrule to them?
The reason lists don't have this concept, is because data binding has no way to display such error data. There's no equivalent to IDataErrorInfo for lists, and so putting a list into an invalid state with a list of broken rules is problematic - there's no pre-existing way to display such error information to the user in Windows, Web or WPF.
I typically just override Save() and check my list-based rules there - throwing a ValidationException if a rule is violated. The UI can handle that exception and give the user some meaningful display indicating the nature of the problem.
Even if BrokenRulesCollection were public, it wouldn't be useful. A broken rules collection from a list wouldn't be listing broken rules per-property, but rather perhaps per-child or something like that. The existing BRC is the wrong type to provide this sort of data. Really, I imagine what you would need from a list is much simpler - just a list of human-readable strings, because they'd never be attached to a specific property, and really shouldn't be attached to a specific child (because if that were the case than that child should be the object that is invalid).
So what you could do is create your own subclass of BLB, declare a protected virtual method like CheckRules() and override Save(). Also in your subclass you'd define a new public property that returns a read-only list of string values.
In Save() you would:
This would roughly mirror the behavior of BusinessBase, and your UI, after catching the exception, could figure out how to display the list of errors to the user.
Obviously your actual business collections would override CheckRules() and would do any collection-level rule-checking there - adding a human-readable text description of any errors into the list of strings.
Hmm... As a work-around, here's a completely untested idea. :)
I think this should work even for empty lists, because as you add objects to it, they will follow the rules.
If you expose the child object's broken rules collection, it can be databound and thus displayed.
As a possible optimization, if you don't want it looping thru the list with every update of every object in it, you might have the rule automatically pass if it's not the first object in the list. If you go this route, you might need to modify the save logic in the list to check whether the first object has any broken rules before saving. Might need some additional UI coding to make for a more pleasant user experience, as a record they weren't working on could suddenly get broken.
Hope that gives you some ideas. Let us know what works!
Check out this thread for one way to implement rules for collections. I use this for my ASP.Net app to return a list of broken rules.
http://forums.lhotka.net/forums/post/7444.aspx
Joe
Hi Andrés,
I’m afraid you have a BUG in your code. Please try this:
1 Execute your example application.
2 Go to the last row of the grid.
3 Type “18/12/2014” in the StartDate column. See that this change makes a conflict with previous row which is marked as invalid (IsValid = False) but the last row isn’t marked as invalid. The last item is not Validated.
The problem is in “DateRangeCollection.vb“. Here you have a possible solution:
<Serializable()> _
Public Class DisjointDecimalIntervalList(Of T As DisjointDecimalIntervalList(Of T, C), C As DisjointDecimalInterval(Of C))
...
Protected Sub ValidateRange(ByVal typeRange As List(Of C), ByVal addedItem As C)
If typeRange.Count = 0 Then
'nothing to do
Exit Sub
ElseIf typeRange.Count = 1 Then
'only one item can't
typeRange(0).ResetDateRangeOverlap()
typeRange(0).ValidateRange()
Exit Sub
End If
'In order to avoid unnecesary nested loops, we make sure none are marked as overlapping first.
'This will not trigger unnecesary validation routines inside the object.
Dim adding As Boolean = addedItem IsNot Nothing
If Not adding Then
For Each i As C In typeRange
i.ResetDateRangeOverlap()
Next
Else
addedItem.ResetDateRangeOverlap()
End If
Dim total As Integer = typeRange.Count - 1
'If Not adding Then
' total -= 1
'End If
For idxi As Integer = 0 To total - 1
Dim i As C = typeRange(idxi)
If adding Then
If Not ReferenceEquals(i, addedItem) Then
If Not i.DateRangeOverlap Then
If i.IsDateRangeOverlapped(addedItem) Then
addedItem.DateRangeOverlap = True
i.DateRangeOverlap = True
End If
ElseIf Not addedItem.DateRangeOverlap Then
addedItem.DateRangeOverlap = addedItem.IsDateRangeOverlapped(i)
End If
End If
Else
For idxj As Integer = idxi + 1 To total
Dim j As C = typeRange(idxj)
If Not ReferenceEquals(i, j) Then
If Not i.DateRangeOverlap OrElse Not j.DateRangeOverlap Then
If i.IsDateRangeOverlapped(j) Then
i.DateRangeOverlap = True
j.DateRangeOverlap = True
'Exit For
End If
End If
End If
Next
End If
i.ValidateRange()
Next
If adding Then
addedItem.ValidateRange()
Else ' Init ******** Solution to the BUG! ***********
Dim lastItem As C = typeRange(total)
lastItem.ValidateRange()
' End ******** Solution to the BUG! ***********
End If
End Sub
...
Tank you very much for your contribution. It has been very helpful to me.
Benjamin
ben.m.s(at)terra.es
PS. I am from Spain so you can speak (write) in Spanish to me if you want to.
Copyright (c) Marimer LLC