So here I am trying to port an application from asp.net 2.0 pre-Linq IIS7 application to a Windows Azure asp.net 3.5 application converting from old ObjectDataSource to LinqToSqlDataSource.
The first thing I discover is why I find myself more and more as I get older not liking the databinding controls. They are TOO black box. If you get an error, often the error is happening inside the black box, with no way to break into the process, examine the variables locals watches and determine exactly what is going wrong. Instead you get a nice generic error like:
Row not found or changed.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.Linq.ChangeConflictException: Row not found or changed.
that tells you nothing! Ok, what exactly does that mean? Quick Bing Search (Bing Is Not Google) and I find this log entry WCSF ObjectContainerDataSource with LINQ to SQL Where in he tells me that in his case the LinqToSql Data Source was trying to find a row using the ID of the row AND the timestamp, if he didn’t include it in the DataKeyNames of the GridView, then he got this error. Ok so obviously my LinqToSql Data Source needs more information in order to find the row to update, at least that seems logical. Here is my data diagram
in my case the only key is the Uid (Unique identifier – my column name convention for a Guid, and I never include the name of the object as part of the column’s name, there is only one Uid per table and if it is in there it MUST be the unique identifier for that table, less typing, a column name DOES have a object name in-front of “Uid” then it by definition is a ForeignKey back, self documenting columns, but enough with my conventions editorial). Because it is a Guid this should be sufficient, to find the correct row for updating but in this case LinqToSql Data Source thinks it’s not (for the auto generated update).
I could use a stored procedure, but first let’s see if we can figure this one out. I see that the ClientProfile is related to Booking by a Has A relationship. So I’ll make an educated guess that LinqToSql, just to make sure it is finding the correct row, is tacking on an additional lookup against the ClientProfile the booking is related to. So I decide to add the ClientProfileUid to the DataKeyNames, and Viola, that bug is smashed but now we have another one
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Gee isn’t that helpful?! And no way for me to break into the place where it is happening and see what object is the problem.
So the stack tells me that it is trying to do an Original Values Match and something is null. Wouldn’t it be REALLY helpful if MS would give me the Key name from the dictionary (second line in the stack)? But of course they don’t so I’m flying blind in a black box.
I suppose a stored procedure is looking better and better!
I had hoped this blog entry would end with the information necessary to tell us how to get past the problem, but unfortunately, without rewriting the app from scratch (it has some significant warts, due to the fact it was originally a learning exercise for a beginning programmer), 3 hours into it, I still can’t figure it out, and the black box of the DataSource just won’t let me see what the problem is (the break on exception just isn’t working the way it should), I gave up and went back to the stored procedure for the update, as it had been used in the previous incarnation.
This entire app is slated for rewrite upon release of .net 4.0 (and it will be done in MVC with NO BLACK BOXES)!