Validation of collection

Validation of collection

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


chris_7t posted on Wednesday, June 07, 2006

Hi,

I'm just starting to use CSLA .NET 2.0  using C#.

I have a collection derived from ReadOnlyListBase where I store some FormatInfo items.

In a creation dialog I want to make sure that the user does not add an item with a name that already exists. I don't add anything to the list I just store existing formatInfo items.

How do I validate the name?

Do I make a validation rule on the formatInfo class (read only class)?

As I understand it, CSLA does not support validation of collections.

Regards,

Chris


ajj3085 replied on Wednesday, June 07, 2006

This is something on my wishlist personally.  You could have the root object which contains the collection as a property and have the root responds to ListChanged events raised by the collection. 

I'd put the actual check logic in the collection though as an internal method.  When the root catches the ListChanged, it calls the internal method.  The method returns if the rule is broken and the root passes this along.

That's how I'd handle it... but i'm not sure a good way if the collection is actually a root object. 

Any other ideas?
Andy

RockfordLhotka replied on Wednesday, June 07, 2006

Certainly there's no concept of doing validation on a read-only list or object. Since they are read-only they can't be changed, so there's nothing to validate.

In your scenario there must be some other, editable, object that you are using to add the new item. It is in that object that the validation must occur.

If you are allowing the user to atomically add a new item (like Format?) outside the context of a parent collection, then the only way to avoid collisions is during the save operation itself. The only way to know for sure that there's not a duplicate is by checking the other data in your database. While you could implement a helper validation rule that scans your read-only list for duplicates, that is just a best-guess and isn't the final word (at least in any multi-user setting).

ajj3085 replied on Wednesday, June 07, 2006

Of course the wishlist is to add validation to editable collections. :-)

No more posting when I'm not fully awake..

jwooley replied on Wednesday, June 07, 2006

Brian's solution requires that the parent hold the business rule. If you would prefer that the collection object hold the rule, then the collection would monitor Add and Remove to set the rule. The parent object would need to override IsValid to return MyBase.IsValid AndAlso _ChildCollection.IsValid. Using the later method allows you to have the parent object look all the way up it's tree with each branch being responsible for reporting it's validity level. In that regard, the collection would iterate it's children to see if they are valid and also impose the custom rule in the collection. The child can then handle valid for itself and any child objects. On and on all the way up the tree.

Jim Wooley
http://devauthority.com/blogs/jwooley/default.aspx

RockfordLhotka replied on Wednesday, June 07, 2006

This is why IsValid is Overridable/virtual in BusinessListBase - so you can override it to implement collection-wide rules if needed (must make sure to call the base implementation too!!). Jim's suggestion of checking the rules in Add/Remove is wise - but should also include Set and in a ListChanged event handler.

ajj, I haven't added validation to editable collections because I'm not really sure what form that would take. In other words, what would you expect such validation logic to look like within your collection class? I think the concept is a great one, I just haven't thought of a clear solution in terms of design/usage.

Jav replied on Wednesday, June 07, 2006

I faced that problem in CSLA1.0.  I did finally eek out a solution which has been working, but I sooooo wished there was some validation mechanism in Editable Collections.  Here is the scenario that I faced.

All Persons and Organizations can have 0...many addresses.  All addresses are in a single DB table.  If the entity has more than one address, one of the addresses must be marked as a Default so that in situations where the UI etc only wants a single address for a given entity, the DB will know which one to serve up.

Problem is further complicated because a given Person (or organization) can wear many hats, and the "Default" address of given entity may depend on the hat placed on the entity by the UI (or DB) etc. at that given moment.

When I bring up a Person, along with the collection of addresses, I need to evaluate if One and Only One address is marked as Default - and if not a rule must be broken.  The way I handled it was to insert another object (Entity) in the hierarchy between a Person (or organization) and its Addresses (or Phones, or Emails), and create a rule for that Entity Object. 

Hence Entity.IsValid meant, among other things, that each of its collections that have > 1 item, had one of the items marked as Default. 

Thus, there are situations in which, each member of a collection may be Valid, but the collection itself may not be valid at a given moment. It may help to have a simpler mechanism to evaluate that.

Jav

 

ajj3085 replied on Wednesday, June 07, 2006

Jav,

Sounds like a good workaround.  I have similar rules for for phone numbers (you can list as many cell phones for the contact as you want, but you may only select one as a default).

Rocky,

I would think that almost always you'd be looping over the collection, to enforce concepts such as Jav has discussed.  I would think that the collection would be able to check its rules (similar to how rules are checked for an individual property, but for collections rules on properties don't make sense) before the ListChanged event is raised.

Currently I handle the situtation by overriding the collections IsValid and running through the collection.  The parent listens for the collections ListChanged event and raises PropertyHasChanged for the parents IsValid property.  This correctly disables the save button.

Ideally though, you might do something like raise a property changed event for the collection property, and then you should be able to use an ErrorProvider.  In my case, the collection is tied to a DataGridView, so I'd think the error provider would appear next to it (since its bound to the property).  The problem is though that error providers show up for my root's invalid properties, and error icons show for missing data within the grid (a list of phone numbers, and you must enter a number).  But if the user selects more than one primary cell phone, I don't have a good way to tell them whats wrong.  I could loop through the collection, find that all the children really are valid, and than assume its this rule that's broken, but that falls apart if I need to add another rule (for example, Home phone number is required).  Also, IsValid would get pretty intense, as its looping through the collection multiple times to check for broken rules.

I admit I haven't thought through all the details, but off the top of my head it sounds like it would work.

Andy

DCottle replied on Friday, June 22, 2007

Has anyone come up with a good solution or this?

 

my scenerio is simple.  I have an editable collection of Product objects.  Each product has a ProductName property.  No two products can have the same ProductName.

I am displaying the objects in a grid that supports the System.ComponentModel.IDataErrorInfo interface and I would REALLY like it if the invalid condition could somehow mark the individual objects as invalid since that would make the grid display each row as invalid when the same name was entered 2 times.

Waiting for someone smarter than me...

David

malloc1024 replied on Friday, June 22, 2007

Raise an event to the collection when the ProductName property changes on a product object.  Pass a reference of the product object when the event is raised.  The Collection should loop through the product objects to check if there are duplicate product names.  If there are, call a method on the product object to set the “duplicate product name” rule to true.  If there isn’t a duplicate product name, call a method on the product object to set the “duplicate product name” rule to false.  I did this on CSLA 1.0 and it worked.

RockfordLhotka replied on Friday, June 22, 2007

You want both rows to go into error, or just the new one?

 

The new one is easy: put a rule on your Name property that simply loops through the Parent collection (a child has reference to its parent) looking for a match of the value. If you find one, return false. The Admin.Roles class in ProjectTracker does this.

 

If you want both to go into error it is a little harder, because you’ll need to put a Friend/internal method on your child class so the new object, when it finds a match (using the same algorithm I just described) can tell the matching object to invoke its own rule check for the Name property. To avoid duplicate work and/or a recursive issue, you’ll need to do some extra work: an extra rule method that just goes false at priority 0, and the Parent-scan rule at priority 1.

 

Rocky

 

 

From: DCottle [mailto:cslanet@lhotka.net]
Sent: Friday, June 22, 2007 12:50 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Validation of collection

 

Has anyone come up with a good solution or this?

 

my scenerio is simple.  I have an editable collection of Product objects.  Each product has a ProductName property.  No two products can have the same ProductName.

I am displaying the objects in a grid that supports the System.ComponentModel.IDataErrorInfo interface and I would REALLY like it if the invalid condition could somehow mark the individual objects as invalid since that would make the grid display each row as invalid when the same name was entered 2 times.

Waiting for someone smarter than me...

David



DCottle replied on Friday, June 22, 2007

Brilliant!  The new row in error was sufficient, and very simple thanks to malloc1024 suggestion above.

 

I may have bastardized my objects, because I do not seem to be able to get to the Parent collection from my object.  What is this reference supposed to be called so I can track down what I screwed up?

Thanks again Rocky and malloc...

 

David

 

RockfordLhotka replied on Friday, June 22, 2007

If your collection is a BusinessListBase then Parent should be a protected property of your child object.

 

If the parent is an EditableRootListBase then the Parent property is null/Nothing because the object isn’t a “child”.

 

It could be that the Parent property is marked as hidden to Intellisense, but it is there.

 

Rocky

 

 

From: DCottle [mailto:cslanet@lhotka.net]
Sent: Friday, June 22, 2007 3:13 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Validation of collection

 

Brilliant!  The new row in error was sufficient, and very simple thanks to malloc1024 suggestion above.

 

I may have bastardized my objects, because I do not seem to be able to get to the Parent collection from my object.  What is this reference supposed to be called so I can track down what I screwed up?

Thanks again Rocky and malloc...

 

David

 



Vinodonly replied on Monday, January 28, 2008

I'm facing this same issue. I have a collection which is having a Percentage field. The total of this percentage field should be 100. But suppose if I have 2 records with percentage of 60 & 40 then a error is thrown as soon as the record is loaded from database or a new record is added.

 

How I can disable that error, can somebody pls help.

Copyright (c) Marimer LLC