Best practices for handling unique constraint violation at UI level - database

While working in my application i came across a situation in which there are likely chances to Unque Constraints Violation.I have following options
Catch the exception and throw it back to UI
At UI check for the exception and show approrpriate Error Message
This is something different idea is to Check in advance about the existance of the given Unique value before starting the whole operation.
My Question is what might be the best practice to handle such situation.Currently we are using combo of Struts2+Spring 3.x+Hibernate 3.x
Thanks in advance
edit
In case we decide to let database give tha final verdict and we will handle the exception and propagte that exception to UI and will show Message as per the Exception.What you suggest should be propagate the same exception (org.hibernate.exception.ConstraintViolationException) to UI layer or should we create a seperate exception class for this since propagating Hibernate exception to UI means polluting the UI classes with Hibernate specific imports and other things

The best way to answer this question is to split it into two ideas.
1) Where is the unique constraint ultimately enforced? In this case (from your question) the answer is the database.
2) How can we make the user experience better by checking the constraint in other places?
Because the database will ultimately make the decision within a transaction, there is no useful check you can make ahead of time. Even if you check before inserting, it is possible (though usually highly unlikely) that another user inserts that value in time between the check and the actual insert.
So let the database decide and bubble the error back up to the UI.
Note that this is not always true for all constraints. When checking foreign keys for small tables (such as a table of US States or Countries or Provinces), the UI provides the user with a selection list, which forces the user to pick an allowed value. In this case the UI really is enforcing the constraint. Though of course even in that case the database must make the final enforcement, to protect against malicious hand-crafted requests to the web layer that are trying deliberately to put in invalid values.
So, for some constraints, yes, let the UI help. But for unique constraints, the UI really cannot help because the database is the final authority, and there is no useful check you can make that you can guarantee will still be true when you make the insert.

Depends on the UI and if the user can do anything about it, as well as what else is going on in the system. I usually check before attempting an insert, especially if there's any sort of transactional logic, or other inserts happening after this one. If there's nothing like that, and the user can just pick a different number to put in, then catching the exception and displaying an error message might be just fine.

Related

Winforms DevExpress UnitOfWork - Check if the values to save from UnitOfWork aren't already in the database

In an application we inherited (Winforms) based on DevExpress, an object of type UnitOfWork is used to keep track and save multiples records in the database.
Usually around 100 objects can be saved in the database on a button click using the method UnitOfWork.CommitChanges();
The table where the records are inserted has an unique constraint on a column.
It might happen that different users try to treat the same entities and to try to enter in that table the same value in the unique column.
So definitively before using UnitOfWork.CommitChanges() we should test if one or more values do not exist already in the database.
What would be the best approach to test if one or more objects are not already in the database before calling UnitOfWork.CommitChanges(), so that we can surely warn the user on his validation?
Thank you
It's not really the DevExpress way of working, see the help topic on auto-generated keys.
However, since you have inherited the code, you could use UnitOfWork.GetObjectsToSave() to obtain an ICollection of the IXPObjects you are about to commit. From this collection you could generate a list of potential key conflicts. Then you could use UnitOfWork.ExecuteScalar() to run a direct SQL command to determine if there are conflicts and resolve them.
The UnitOfWork.CommitChanges() calls CommitTransaction, so you could perform this check in one of the UnitOfWork events such as UnitOfWork.BeforeCommitTransaction.
As with everything DevExpress, your best support option is the DevExpress Support Center.
The functionality you ask for is not possible to implement in a multiuser system. As every user (necessarily) works in his own database transaction, there is always a chance for a user to insert a datarow with a key that another user inserted right before. You could only avoid this by employing database mechanisms like autogenerated keys. But I think this is not applicable for you.
So I suggest to catch the exception thrown by commitChanges and act upon it.

Are unique constraints on the DB necessary?

I've been wondering lately. Lets say we're doing a webapp with JSF+Spring+JPA/Hibernate (or well any other technologies) and lets say we have a "User" entity. We want the User to have a unique login. If we want to do it then we can put a #UniqueConstraint on the "Login" column, but still our application has to check during user registration whether the user input is valid (unique) or not, without that and only with the DB constraint we will simply get an error. This made me think, are DB constraints really necessary/helpful? The only two times I can think off when they would give us any benefits would be when someone tries to hack us (but I guess our app should be SQL injection proof anyway) or we try to change the DB content manually (which shouldn't really happen). Actually now that I think about it, are DB constraints in general necessary/good practice? Like the lenght of a string etc.
For me, categorically yes, see Database as a Fotress by Dan Chak from 97 Thinks Every Software Architect Should Know. He says it much better than I could.
Yes, they are. They enforce data integrity at the lowest level.
You might want to change DB content manually(i.e upgrades to new version)
You might forget to check some constrain in your code.
You can look at this like client/server validation. Your program is client, db is server. Mostly client validation is enough, but you must have server validation just in case something goes wrong.
I think a data person would say both are absolutely necessary. Your question assumes that your middle tier application code will be in front of that database now and forever.
The truth is that middle tier applications come and go, but data lives forever.
There's no getting away from length of columns in schema design. I think you're asking if it's a good practice for the middle tier to enforce them. Maybe not, but they're key for the database.
Often when you declare a set of columns to be unique, it's something that you will want to query by - so it should most likely be indexed anyway.
Yes your application should do the appropriate checking, but what if a mistake slips through? If your database knows something is meant to be unique, at least you know you won't store invalid data (or not "badly" invalid data, like duplicates of data intended to be unique). At any rate you could ask the opposite question: what does it cost you?
If you want to have bad data, then take off the unique constraints in the database. I have worked around databases since the 1970's and have queried or imported data stored in hundreds of databases. I have never seen good data in databases where the constraints are improperly set at the application level. Many things other than the application hit the database (imports from other systems, a quick update to prod data to fix a data issue that is run from the query window, other applications, etc.). Many times the application is replaced and the constraints are lost.
Constraints, both unique and foreign not only enforce data integrity, but they have performance implications. Without knowledge of these 'informal' constants, database optimizers are going to make unpredictable decisions about how to execute your statements.
but still our application has to check
during user registration whether the
user input is valid (unique) or not,
without that and only with the DB
constraint we will simply get an
error.
That's the funniest thing I've ever read. You simply get an error? That's really all you need right? Ever heard of error trapping? Try Catch ring any bells?
It's actually very counter productive for your app to "check". The database is going to check anyways on the constraint so why do it twice. The app should just insert the row as if it will be fine. The DB will check for uniqueness and raise an error on a failure... You app should CATCH that error and do whatever you were doing in your existing check.
Yes. Just catch the key violation error and the key constraint will have done the work for you without having to incur an additional overhead of an additional check first.

Unit of Work - What is the best approach to temporary object storage on a web farm?

I need to design and implement something similar to what Martin Fowler calls the "Unit of Work" pattern. I have heard others refer to it as a "Shopping Cart" pattern, but I'm not convinced the needs are the same.
The specific problem is that users (and our UI team) want to be able to create and assign child objects (with referential integrity constraints in the database) before the parent object is created. I met with another of our designers today and we came up with two alternative approaches.
a) First, create a dummy parent object in the database, and then create dummy children and dummy assignments. We could use negative keys (our normal keys are all positive) to distinguish between the sheep and the goats in the database. Then when the user submits the entire transaction we have to update data and get the real keys added and aligned.
I see several drawbacks to this one.
It causes perturbations to the indexes.
We still need to come up with something to satisfy unique constraints on columns that have them.
We have to modify a lot of existing SQL and code that generates SQL to add yet another predicate to a lot of WHERE clauses.
Altering the primary keys in Oracle can be done, but its a challenge.
b) Create Transient tables for objects and assignments that need to be able to participate in these reverse transactions. When the user hits Submit, we generate the real entries and purge the old.
I think this is cleaner than the first alternative, but still involves increased levels of database activity.
Both methods require that I have some way to expire transient data if the session is lost before the user executes submit or cancel requests.
Has anyone solved this problem in a different way?
Thanks in advance for your help.
I don't understand why these objects need to be created in the database before the transaction is committed, so you might want to clarify with your UI team before proceeding with a solution. You may find that all they want to do is read information previously saved by the user on another page.
So, assuming that the objects don't need to be stored in the database before the commit, I give you plan C:
Store initialized business objects in the session. You can then create all the children you want, and only touch the database (and set up references) when the transaction needs to be committed. If the session data is going to be large (either individually or collectively), store the session information in the database (you may already be doing this).

How to handle db constraint violations in the user interface?

We implement the majority of our business rules in the database, using stored procs.
I can never decide how best to pass data constraint violation errors from the database back to the user interface. The constraints I'm talking about are tied more to business rules than data integrity.
For example, a db error such as "Cannot insert duplicate key row" is the same as the business rule "you can't have more than one Foo with the same name". But we've "implemented" it at the most common sense location: as a unique constraint that throws an exception when the rule is violated.
Other rules such as "You're only allowed 100 Foos per day" do not cause errors per-say, since they're gracefully handled by custom code such as return empty dataset that the application code checks for and passes back to the ui layer.
And therein lies the rub. Our ui code looks like this (this is AJAX.NET webservices code, but any ajax framework will do):
WebService.AddFoo("foo", onComplete, onError); // ajax call to web service
function onComplete(newFooId) {
if(!newFooId) {
alert('You reached your max number of Foos for the day')
return
}
// update ui as normal here
}
function onError(e) {
if(e.get_message().indexOf('duplicate key')) {
alert('A Foo with that name already exists');
return;
}
// REAL error handling code here
}
(As a side note: I notice this is what stackoverflow does when you submit comments too quickly: the server generates a HTTP 500 response and the ui catches it.)
So you see, we are handling business rule violations in two places here, one of which (ie the unique constaint error) is being handled as a special case to the code that is supposed to handle real errors (not business rule violations), since .NET propagates Exceptions all the way up to the onError() handler.
This feels wrong. My options I think are:
catch the 'duplicate key violation' exception at the app server level and convert it to whatever it is the ui expects as the "business rule violated" flag,
preempt the error (say, with a "select name from Foo where name = #Name") and return whatever it is the app server expects as the "business rule violated" flag,
in the same ballpark as 2): leverage the unique constraint built into the db layer and blindly insert into Foo, catching any exceptions and convert it to whatever it is the app server expects as the "business rule violated" flag
blindly insert into Foo (like 3) and let that Exception propagate to the ui, plus have the app server raise business rule violations as real Exceptions (as opposed to 1). This way ALL errors are handled in the ui layer's onError() (or similar) code.
What I like about 2) and 3) is that the business rule violations are "thrown" where they are implemented: in the stored proc. What I don't like about 1) and 3) is I think they involve stupid checks like "if error.IndexOf('duplicate key')", just like what is in the ui layer currently.
Edit: I like 4), but most people say to use Exceptions only in exceptional circumstances.
So, how do you people handle propagating business rule violations up to the ui elegantly?
We don't perform our business logic in the database but we do have all of our validation server-side, with low-level DB CRUD operations separated from higher level business logic and controller code.
What we try to do internally is pass around a validation object with functions like Validation.addError(message,[fieldname]). The various application layers append their validation results on this object and then we call Validation.toJson() to produce a result that looks like this:
{
success:false,
general_message:"You have reached your max number of Foos for the day",
errors:{
last_name:"This field is required",
mrn:"Either SSN or MRN must be entered",
zipcode:"996852 is not in Bernalillo county. Only Bernalillo residents are eligible"
}
}
This can easily be processed client side to display messages related to individual fields as well as general messages.
Regarding constraint violations we use #2, i.e. we check for potential violations before insert/update and append the error to the validation object.
The problem is really one of a limitation in the architecture of your system. By pushing all logic into the database, you need to handle it in two places (as opposed to building a layer of business logic that links the UI with the database. Then again, the minute you have a layer of business logic you lose all the benefits of having logic in stored procs. Not advocating one or the other. The both suck about equally. Or don't suck. Depending on how you look at it.
Where was I?
Right.
I think a combination of 2 and 3 is probably the way to go.
By pre-empting the error you can create a set of procedures that can be called from the UI-facing code to provide detailed implementation-specific feedback to the user. You don't necessarily need to do this with ajax on a field-by-field basis, but you could.
The unique constraints and other rules that are in the database then become the final sanity-check for all data, and can assume that data is good before being sent, and throw Exceptions as a matter of course (the premise being that these procedures should always be called with valid data and therefor invalid data is an Exceptional circumstance).
In defense of #4, SQL Server has a pretty orderly hierarchy of error severity levels predefined. Since as you point out it's well to handle errors where the logic is, I'd be inclined to handle this by convention between the SP and the UI abstraction, rather than adding a bunch of extra coupling. Especially since you can raise errors with both a value and a string.
A stored procedure may use the RAISERROR statement to return error information to the caller. This can be used in a way that permits the user interface to decide how the error will appear, while permitting the stored procedure to provide the details of the error.
RAISERROR can be called with a msg_id, severity and state, and with a set of error arguments. When used this way, a message with the given msg_id must have been entered into the database using the sp_addmessage system stored procedure. This msg_id can be retrieved as the ErrorNumber property in the SqlException that will be raised in the .NET code calling the stored procedure. The user interface can then decide on what sort of message or other indication to display.
The error arguments are substituted into the resulting error message similarly to how the printf statement works in C. However, if you want to just pass the arguments back to the UI so that the UI can decide how to use them, simply make the error messages have no text, just placeholders for the arguments. One message might be '"%s"|%d' to pass back a string argument (in quotes), and a numeric argument. The .NET code could split these apart and use them in the user interface however you like.
RAISERROR can also be used in a TRY CATCH block in the stored procedure. That would allow you to catch the duplicate key error, and replace it with your own error number that means "duplicate key on insert" to your code, and it can include the actual key value(s). Your UI could use this to display "Order number already exists", where "x" was the key value supplied.
I've seen lots of Ajax based applications doing a real-time check on fields such as username (to see if it already exists) as soon as the user leaves the edit box. It seems to me a better approach than leaving to the database to raise an exception based on a db constraint - it is more proactive since you have a real process: get the value, check to see if it is valid, show error if not, allow to continue if no error. So it seems option 2 is a good one.
This is how I do things, though it may not be best for you:
I generally go for the pre-emptive model, though it depends a lot on your application architecture.
For me (in my environment) it makes sense to check for most errors in the middle (business objects) tier. This is where all the other business-specific logic takes place, so I try to keep as much of the rest of my logic here too. I think of the database as somewhere to persist my objects.
When it comes to validation, the easiest errors can be trapped in javascript (formatting, field lengths, etc.), though of course you never assume that those error checks took place. Those errors also get checked in the safer, more controlled world of server-side code.
Business rules (such as "you can only have so many foos per day") get checked in the server-side code, in the business object layer.
Only data rules get checked in the database (referential integrity, unique field constraints, etc.). We pre-empt checking all of these in the middle tier too, to avoid hitting the database unnecessarily.
Thus my database only protects itself against the simple, data-centric rules that it's well equipped to handle; the more variable, business-oriented rules live in the land of objects, rather than the land of records.

Should I check for DB constraints in code or should I catch exceptions thrown by DB

I have an application that saves data into a table called Jobs. The Jobs table has a column called Name which has a UNIQUE constraint. The Name column is not PRIMARY KEY. I wonder if I should check for duplicate entries myself before I try to save/update a new entry or if it's better to wait for an exception thrown by the data access layer. I'm using NHibernate for this App if it's of any importance
Thanks to everybody for the great input.
I have found one more reason why I should validate in code and not just wait for an exception being thrown (and caught by my code). It seems that NHibernate will only throw an NHibernate.Exceptions.GenericADOException which is not very informative regarding the cause of the exception in this case. Or am I missing an aspect of NHibernate here?
The answer is: both.
If your database has constraints it can guarantee certain invariants about the data, such as uniqueness. This helps in several ways:
If you have a bug in your
application, violating the
constraint will flag something that
might otherwise not be noticed.
Other users of the database can
assume more about the behaviour of
the data as the DBMS enforces
invariants.
The database protects itself from
incorrect updates that violate the
constraints. If you find you have some other
system or interface populating the
database down the track, the
constraints enforced by the database
mean that anything caught by the
constraints won't (or at least
is less likely to) break your system.
Applications and databases live in a M:M relationship in any but the most trivial cases. The application should still have the appropriate data and business rule validations but you should still not plan for your application being the only customer of the data. Work in data warehousing for a few years and you'll see the effects of applications designed by people with this mindset.
If your design is good (both database and BL), the database shouldn't have any constraints that wouldn't be dealt with in the BL - i.e. you shouldn't be presenting the database with inconsistent data. But nothing is perfect.
I've found that confining the database to data consistency constraints lets me handle all BL validation in procedural code, and the only cases where I experience database exceptions are design and coding errors which can (and should be) fixed.
In your case, checking the name for uniqueness is data content validation, properly handled in code. Which presumably catches the error nearest the point of commission, where you hopefully have friendlier UI resources to call on without introducing undesirable coupling between abstractions.
I would leave that work entirely to the database; your code should focus on catching and properly handling the exception.
Reasons:
Performance- The database will be
highly optimized to enforce
constraints in a fast and efficient
way. You won't have time to
optimize your code as well.
Maintainability- If the constraints
change in the future, you won't have
to modify your code, or perhaps you
will just have to add a new catch{}.
If a constraint is dropped, you
won't have to touch your code at
all.
If you are going to check the constraints yourself, do it in the data access layer. Nothing above that layer should know anything about your database or its constraints.
In most cases I'd say leave it to the DAL to catch DB-originated exceptions. But in your specific case, I think we're talking about basic input validation. I'd opt for a name availability check call to the database, before submitting the whole form.
You should definitely check for any exception thrown by the data access layer. The problem with checking if there is a record with the same value is, that it requires you to lock the table for modifications until you insert the new record to prevent race conditions.
It is generally advisable to check for exceptions/errors, even if you have checked everything yourself before. There is almost always something that can go wrong or which you haven't considered in your code but is enforced by the database.
Edit: If I understand the question right, it is not about if the constraint should be enforced by the database or not, but how to deal with it in the application code. Of course you should always set up all constraints in the database to prevent bad data entering your database.
The question that you need to answer is:
"Do I need to present the user with nice messages". Example: There is already a Job with the name TestJob1.
If the answer is No, just catch the error and present a common message
If the answer is Yes, keep reading
If you catch the error after the insert there isn't enough information to present the right message (at least in an agnostic DB way)
On the other hand, there can be race conditions and you can have simultaneous transaction trying to insert the same data, therefore you need the DB constraint
An approach that works well is:
check before to present a nice
message
catch the exception and
present a common error message
(assuming this won't happen very
frequently)
Personally I'd catch the exception. It's much simpler and requires much less code.
The inner exception of the GenericADOException will tell you why the database action failed. You can catch the OracleException / MSSQLException / [InsertCustomExceptionHere] and handle the error from that message. If you want to pass this back up to the front end (assuming the user is the one who entered duplicate data) you might want to wrap it in a custom exception first so you don't couple your front end to your database. You don't really want to be passing RDBMS specific exceptions around.
I disagree with checking the db for uniqueness before doing an insert, round tripping to the database twice isn't very efficient and certainly isn't scalable if you have a high volume of user traffic.

Resources