- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
LLBlGenProDataSource2 Validation
Joined: 12-Jan-2007
Version LlblGenPro2 2.0.0.0 (Dec 6th 06) Scenario : Adapter
Field validation without using asp.net validators. If a user enters a value which does not match the field datatype and saves, the entity is persisted with the associated field set to null if the db allows this.
For an entity with field of data type number
OriginalDbValue UserEnteredValue DbPersistedValue 9990 999x <undefined> (null)
After the save the original value is lost. No error results if the user enters incorrect data.
Field validation using asp.net validators. See the recently released c# db editor templates for an example of this one. For a date datatype three textboxes are produced one for day (Range validator 1-31),one for month (Range validator 1-12) and one for year (RegEx Validator 4 numbers).
OriginalDbDate UserEnteredDate DbPersistedValue 28/02/2007 29/02/2007 <undefined> (null)
Again the original data is lost. No error results from the ASP range/regex validators as this within bounds. However it is plainly not a valid date as this month ends on the 28th.
LlblgenProDataSource2 Class flow
ExecuteUpdate or ExecuteInsert --> SetEntityValue --> base.ConvertValueToDestinationType
Notes base.ConvertValueToDestinationType if no conversion possible, null is returned In the above cases this happens as 999x is not a number and 29/02/2007 is not a date.
--> Entity.SetNewFieldValue(field.name, <b>NULL</b>) --> Field set to null, then persisted. Original value lost. No error message returned.
It seems that LLBLGenPro is totally reliant on ASP.NET validators and as I've shown even with these its still possible to cause damage to the db.
I understand that the current version of 2 way binding in asp.net 2 is a bit useless, but even that throws an exception when trying to set a non valid value.
Please validate the contents of the newValues dictionary against the field datatype. Either throw an exception at the first error aka standard asp.net2 object datasource method, or validate all the new values and if any fail raise an exception with the invalid fieldnames. Before making changes to the object.
If I have a field value and nothing is returned from the convert function surely there must be something wrong.
Please check this out asap
Cheers
Shorty
Joined: 12-Jan-2007
Walaa
Thanks for the reply, but am I correct in assuming the datasource control put values into the entity??
DataSource --> Entity --> Database.
Its the datasource thats the problem. This has set the property in the entity to null if it cannot convert the value.
The field may well be a generic nullable(of T). Therefore an acceptable entry is nothing, how do I validate this is correct.
e.g. (1) User clears field in form. Sets property to null.
(2) Datasource cannot map datatype. Sets property to null.
Both result in null and are permissable in the db. However in the second case this is not what the user requested. **How can I use entity validation when I cannot guarantee the entry in the entity is the correct one? **
The datasource control gets string values only from asp.net. This might mean that there are problems with the data, i.e. not convertable to the type it actually represents.
The datasourcecontrol can do two things in the case when a conversion can't be done: 1) detect that something is off and throw an exception 2) return null and live on.
With 1), the datasourcecontrols become pretty much useless. The thing is: datasourcecontrols are used declarative, so there's no way to try/catch the set action. So what to do with the error? The user isn't helped with an exception, so we opted for 2, return null. If the field isn't nullable, the value is ignored.
Another reason is that it's common practise to validate values before they're accepted, e.g. via validators on the page. I know this can be awkward, but it's in THIS case the proper place to do this validation.
So what should happen, according to you , if the conversion fails? I really don't know any other solution which really helps. As you pointed out, the field might be a nullable field and thus null is an acceptable value and the entity validator, even a validation on BeforeSave, will accept the value.
The thing is that the exception pretty much halts the complete page, and because it's used declarative, there's no spot to place the try/catch to handle the exception and move on.
Is the only solution to ignore the value also when the field is nullable?
Joined: 12-Jan-2007
Otis
I guess one possibiltiy if you do not wish to throw an exception is to use setdataerror for the field with an appropriate message each time a failed binding occurs. Then test the entity for error as idataerrorinfo before saving to database.
Perhaps a switch to ignorebindingerrors on the datasource control. So it works as now but for others who wish an additional level of security as simple test such as the following may do the trick.
performwork dim da as new dataaccessadapter for each entity to insert/update in datasource control dim idi as idataerrorinfo = ctype(ent,idataerrorinfo) if idi.error is string.empty ent.save end if; end loop
Shorty wrote:
Otis
I guess one possibiltiy if you do not wish to throw an exception is to use setdataerror for the field with an appropriate message each time a failed binding occurs. Then test the entity for error as idataerrorinfo before saving to database.
That's string based, and UI oriented code, I won't use that interface, as validation for the ENTITY shouldn't be bound to UI. Though I can propagate back an error report inside the datasource control, that's not the problem. The problem is: what should be done with the field?
Looking at it again with fresh eyes, I think ignoring the value is best, as it is also ignored if the field is not nullable and there was an error. Well... 'best' is an understatement, but that's all that can be done, as there's little left what can be done at THAT point.
Perhaps a switch to ignorebindingerrors on the datasource control. So it works as now but for others who wish an additional level of security as simple test such as the following may do the trick.
performwork dim da as new dataaccessadapter for each entity to insert/update in datasource control dim idi as idataerrorinfo = ctype(ent,idataerrorinfo) if idi.error is string.empty ent.save end if; end loop
Though that would lead to an entity not being saved. It's not really solvable properly IMHO, due to the declarative nature of the datasourcecontrol: all it can do is ignore values if they're wrong, but acting upon a failure is undefinable, because where to put the logic?
Part of me is also in the camp that says: "you then should have validated the values with validators in the page".
The thing is: value input is really a 2-step process: the first step is the UI itself, i.e. the browser form. Nothing is set into the entities at that point. Then the postback comes, and the values are set into the entity or in the case of Ajax, multiple entities can be updated at once. When something goes wrong THERE, the whole process of handling the post-back stops, as there's no code behind running, it's all declarative. So without code-behind code which validates the values manually, the code can only assume the values were valid. I can't find anything on the ObjectDataSource control as well to handle this.
Setting the IDataErrorInfo elements is a small thing, but really doesn't give much help, as the errors aren't in localized text, so they should be parsed, but where?
I could add an event which is raised when there's an invalid value passed in, though would that really help?
Joined: 12-Jan-2007
Otis
Thanks for the reply. I must disagree with you in that if the base.ConvertValueToDestinationType cannot be performed. ie. not null value goes in and null comes out then there must be a problem. Surely ignoring it is just dangerous. I'd rather exceptions been thrown all over the place so long as my data integrity is maintained.
I can handle exceptions what I can't handle is data loss.
Consider a field which is incremented by some type of logic. e.g. current value 1000. User updates with 100q rather than 1001 resulting in null saved to db. All because my new team member isnt aware that asp validators are crucial. Perhaps he/she choose entity validation rather than datatype validation unaware the problem has occured before the entity is loaded with data.
If I use a standard object datasource and bind values to an object data type. It may be rubbishy but at least if it cannot bind the data a standard clr exception is thrown. I can trap this in the formview/gridview handle it and keep it edit/insert mode so my user can alter the data. This works even if validators are not used.
Cheers
Shorty
Joined: 12-Jan-2007
Walaa
How can use the entity to persist the data my user has entered when the datasource control my have altered it before it has reached the entity.
Otis seems to suggest use asp validators on everthing on the page. Sensible advice and will do this anyway. However this one big caveat to this. What happens if I have trigger processing in my formview/gridview
e.g Protected Sub ..... Handles formview.ItemUpdating
e.NewValues("fieldname")=Y
where Y maybe a value retrieved from another source say the query string. Should this value not be converted into the associated .net type for field "fieldname" my database will be corrupted as it will be updated/inserted to null.
I can't put an asp validator on it as it will not exist as part of the form.
Makes for scary programming. I will have to tell my team they can use any form based triggers to auditing etc and that should they miss an asp validator out theyll be making tea for the next few years.
Cheers
Shorty
Shorty wrote:
Otis
Thanks for the reply. I must disagree with you in that if the base.ConvertValueToDestinationType cannot be performed. ie. not null value goes in and null comes out then there must be a problem. Surely ignoring it is just dangerous. I'd rather exceptions been thrown all over the place so long as my data integrity is maintained. I can handle exceptions what I can't handle is data loss.
I think you misunderstood my post. When the postback comes and ExecuteInsert/Update is called, and the datasourcecontrol throws an exception, YOU can't handle it, as there's no try/catch to specify, so the page will show the lovely exception thrown page instead.
THAT's what's the problem. I don't think you want to have that page to show up, so throwing an exception isn't the solution. If you can show me how to catch the exception, OK, I'm all ears but I'm not aware of a method where the datasourcecontrol is specified in the HTML and the exceptions thrown by the datasourcecontrol are trappable AND handleable, so other tasks can continue on the page(!).
I'm not arguing that I can't trap an error in the conversion, that's not the problem, I can report an error up to the caller and it can deal with it there, that's not what's bugging me. What I have a problem with is WHAT to do IF an error occurs. At the moment, null is inserted.
That's perhaps not the best choice, but IMHO the only alternative is to ignore the value, and thus NOT setting the field, as it's already done for non-nullable fields, where the null is simply ignored. To me the alternative of throwing an exception isn't acceptable as the exception isn't catchable, at least I have no idea how I'd do that, but that can be because of my lack of deep asp.net knowledge, so if this is standarized and doable, it's of course an option.
Consider a field which is incremented by some type of logic. e.g. current value 1000. User updates with 100q rather than 1001 resulting in null saved to db. All because my new team member isnt aware that asp validators are crucial. Perhaps he/she choose entity validation rather than datatype validation unaware the problem has occured before the entity is loaded with data.
If I use a standard object datasource and bind values to an object data type. It may be rubbishy but at least if it cannot bind the data a standard clr exception is thrown. I can trap this in the formview/gridview handle it and keep it edit/insert mode so my user can alter the data. This works even if validators are not used.
You can catch the exception in the grid somewhere when the value isn't settable on a property, when this happens on the postback? And if you have multiple entities to set, for example in a grid with ajax support where multiple rows are edited, it works too?
I see in the code that objectdatasource throws exceptions when it can't convert the value, however how would the exception be caught by the bound control?
I don't mind making a switch on the control where the behavior is specified: ignore, set null, throw exception, however to me it should be a useful feature: if an exception isn't catchable by the bound control, it's of no use, as the USER causes the error, but the user has no business with the exception...
So it comes down to: - if the exceptions are catchable by code related to the bound control, e.g. an eventhandler in the grid of whatever, then it's doable to throw an exception - if the exceptions aren't doable, ignoring the value is better, - if people want the current behavior, it can be kept.
I can't find an event on the gridview control where I can add code to catch the exception thrown by option 1. This to me leads to a page showing the exception text, which IMHO is something no-one wants. However, I'm sure I'm overlooking something as you say it is possible, so if you could point me to the right direction I can have a look and add proper code.
Again, it's not about not being able to check if the conversion goes bad, that's simple, what's the problem is what to do with a bad conversion so it's properly handled.
Joined: 12-Jan-2007
Otis
Try looking at formview_itemupdated or iteminserted. A special eventargs is produced. This contains e.Exception and e.ExceptionHandled. If you set e.ExceptionHandled = true the exception is handled by the bound control and not bubbled to the page.
Same for GridView
Have a look and see if this helps
Cheers
Shorty
Thanks for the heads-up, Shorty I'll check these out.
I have to add that I can't add this to the v2.0 build, it will be build into the v2.1 which is currently in development and which is a free upgrade for v2.0 users, because it's an architectural change (new properties) which affect usability.
I could change the v2.0 behavior to ignore the value if the convert fails, as a fix for the issue for v2.0 builds.
Joined: 12-Jan-2007
Otis
Thanks for that and yes a patch to ignore the value will at least stop data corruption. Any ideas when v2.1 will be released? A useful feature would be to pre check the types of all values being bound. Then if 1 or more fails then raise an exception (maybe DataBindingException that conatins all the invalid fields). This would be an improvement on the objectdatasource as currently if there are multiple type errors it's a case of fixing them one by one each time throwing a new exception.
Cheers
Shorty
Shorty wrote:
Otis
Thanks for that and yes a patch to ignore the value will at least stop data corruption.
I'll make that change in todays build, so it will be available very soon. (this week). If you want I can attach it to this thread so you can use it later today.
Any ideas when v2.1 will be released? A useful feature would be to pre check the types of all values being bound. Then if 1 or more fails then raise an exception (maybe DataBindingException that conatins all the invalid fields). This would be an improvement on the objectdatasource as currently if there are multiple type errors it's a case of fixing them one by one each time throwing a new exception.
Good tip, I'll include that.
V2.1's development is likely done at the end of april so then we'll release the beta.