.NET2.0: Microsoft, you got something very wrong in data validation..

M

mcw8

Even Microsoft's own data-validation walkthrough article
(http://msdn2.microsoft.com/en-us/library/1120xds5.aspx) recommends
attaching a handler to the RowChanging event of the DataTable

The problem is, that when editing a row, the RowChanging is raised
after an attempt to update the row in the table. If I attempt to update
a row and alter the primary key to a value that collides with another
row in the table then a ConstraintException occurs without the
RowChanging event firing

Correct me if I'm wrong, but doesnt this make RowChanging absolutely
pointless? I can enter data that is invalid and causes an exception,
yet your data walkthroughs tell me I can use RowChanging to validate
it. Nonsense!
 
D

David Browne

<DIV>&lt;[email protected]&gt; wrote in message
news:[email protected]... said:
(http://msdn2.microsoft.com/en-us/library/1120xds5.aspx) recommends
attaching a handler to the RowChanging event of the DataTable

The problem is, that when editing a row, the RowChanging is raised
after an attempt to update the row in the table. If I attempt to update
a row and alter the primary key to a value that collides with another
row in the table then a ConstraintException occurs without the
RowChanging event firing

Correct me if I'm wrong, but doesnt this make RowChanging absolutely
pointless? I can enter data that is invalid and causes an exception,
yet your data walkthroughs tell me I can use RowChanging to validate
it. Nonsense!

If you have a Constratint to enforce your logic you don't need to validate
it in RowChanging. RowChanging allows you to enforce additional validation
logic.

And why are you allowing a user to update a primary key value in the first
place?

David
 
M

Marina Levit [MVP]

If there was a constaint violation, why would you want to bother validating
anything else? The constraint check is a type of validation - and it already
caught an error. Who cares if there are other validation problems - one has
already been found that makes the change illegal.

And as David points out, it's very odd design to allow the primary key to be
changed.
 
C

cjard

David said:
<DIV>&lt;[email protected]&gt; wrote in message


If you have a Constratint to enforce your logic you don't need to validate
it in RowChanging. RowChanging allows you to enforce additional validation
logic.

The other issue is that, with all the automatic things going on it is
very hard to catch constraintexceptions. If you drop your controls onto
a form from a data source, the BindingNavigator and BindingSources are
created for you, The BindingNavigator has defaults for scrolling the
recordset; 5 ways to be precise. Each of these will invoke an EndEdit
in the bindingsource if used. EndEdit may throw a COnstraintException
and the default implementation provides no way to deal with this other
than crash the app. You end up with a situation where all the helpful
automatic things that got you up and running quickly become the biggest
obstacles that you will forever be tripping over. In my example there
each of those 5 ways of causing a BindingSource to shift position will
need a try/catch block to catch constraintexceptions. Once you've
caught it, there is little you can do without some serious fiddling
about; the controls still show the new values the user typed, but the
underlying value retains the old types. In the bound route from control
to underlying data there is a logical disconnect introduced - the
values int he controls are out of sync with the data, and to date I
have found no obvious way of re-syncing them other than to call some
sompletely unrelated method like
BindingSource.Current.Row.ClearErrors()

I accept your observation that constraints negate the need for
validation, but not when they generate application-halting exceptions
that you cant catch and handle easily

And why are you allowing a user to update a primary key value in the first
place?

It's a compound primary key. A person can have several addresses
throughout their life, so the personID and the effectivedate can be
used to identify which address a person was at at what time. Thing is,
I have to allow the users to edit the effective date of an address, as
we may be notified 3 months in advance that a person is moving house.
We would put a new entry in the system with an advance effective date.
This measure of flexibility introduces a PK violation possibility as
the user may set an effective date that already exists for that
particular person.

Now, the database doesnt particularly care, because it uses a MERGE
statement to perform the update - setting a value that would make an
INSERT violate the PK, ina merge simply causes the existing data to be
updated. Again, that may be a cause for concern but the designers have
chosen to have me decide whether to update based on an algorithm so
that's beyond scope
 
C

cjard

Marina said:
If there was a constaint violation, why would you want to bother validating
anything else? The constraint check is a type of validation - and it already
caught an error. Who cares if there are other validation problems - one has
already been found that makes the change illegal.

Well, the nice thing to do is keep all the user's hard work in typing
out an entire address record and just inform them that the PK is
wrong/collides with another PK and must be changed.

At the moment, I have a torturous route to follow in that I must find
every occasion that a BindingSource's EndEdit method might be called,
and wrap it in a try/catch block to handle the COnstraintException that
will otherwise cause my app to quit. Once I've caught the exception, I
need to handle it nicely, and I really dont see a way to do that. I can
use string manipulation to pull apart the error message and find which
columns are in error (but i'd have expected a ConstraintException to
have a key/value collection for that) but even if I do, and I find the
columns that are in error, there's nothing I can do with that
information..

The data the user typed seems to exist[at this moment in time] in only
one place: the .Text value of the bound textboxes. If we trace the
route from bound textbox, right the way through to the underlying
datatable, we see that the textbox might be displaying "newvalue" but
its underlying data chain contains "oldvalue" at every other step.

I cant believe that I'm considering extending BindingSource to redefine
the EndEdit method thus:
EndEdit()
try{
base.EndEdit()
} catch(constraintException ex){
//pull erroneous columns out of ex.Message
//crawl back through the bindings to find the controls that the
underlying
// values are bound to
//for all columns not in error, set the underlying values to those
the textboxes
// curretly display
//for columns in error, reset the displayed data in the control to
the underlying value
//show a message to the user that the following columns were found
to be in error
// and they have been reset to defaults, user must pick a different
value
}


All i can say is yuck; I expected more of validation than that. Would
it be easier to set mydataset.EnforceConstraints = false, and implement
RowChanging in all my 98 datatables to do specific validation for each?
Such a move takes time; Have i simply hit the performance/simplicity
wall inherent in every RAD system whereby the basic routine is fine if
youre writing some low-grade app but when it becomes a serious tool you
should do away with the automatic provisions of the IDE and code it all
yourself the hard way?

I had high hopes for VS2005 and I'm finding difficulty in having it
meet them. It's entirely possible that this is because I'm using it in
totally the wrong way, but i feel its actually more likely that its
because I have questions that noone can answer (Which reminds me, I
must check to see if anyone has told me why master BindingSources
destroy their related child's Detached data during an EndEdit - this
makes creating related data very hard, and I feel it's another great
example of something MS got very wrong)

And as David points out, it's very odd design to allow the primary key to be
changed.

I dont know if there's a rule that PKs must always be generated by the
system without user interaction but I have the design for a system
where several tables have compound primary keys that the user must be
instrumental in creating. If this is a design no-no then do let me know
and i'll have the designers work it over. For an accurate description
of why the system is designed thus, please see my response to David.

Thanks for your comments :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top