A new exception, UpdateException, was added to .NET 3.5 SP1 in order to support the ADO.NET Entity Framework. This exception is thrown when modifications to the object instances cannot be persisted to the data source.
Great! But how do you distinguish between the different reasons that the objects could not be persisted? In other words, how do you tell that the reason for the failure was due to a duplicate key versus a character field that was too long?
One answer is to validate the data in the business object so that you don’t get the exception in the first place. For field constraints, you could make sure your business object checks for valid field lengths before trying to store the data. For unique keys, you could ensure that the key doesn’t exist before persisting the object (doing so in a transaction, of course, to make sure another record doesn’t sneak in and use the key before you). You could, for example, customize your context object to handle these kinds of issues with techniques like this.
The other option is to interpret the exception being thrown. For example, the InnerException property of the UpdateException object might contain an SqlException object that holds details about errors reported by SQL Server. From there, you could look at the exact error codes to determine what happened. Some of us use a specific naming syntax for our SQL table constraints so that we can more easily identify constraint violations. Of course, this technique more closely associates the business objects with the data persistence layer. As we move towards more persistence-agnostic architectures, it would be nice not to tie our error handling so closely to SQL Server.
To get SQL Server 2005 list of error codes, you can use the T-SQL:
SELECT * FROM sys.messages WHERE language_id = 1033
If I had my choice, a better solution to me would be another hook in the Entity Framework that would allow me to throw specific, strongly-typed exceptions that more clearly identify the errors being generated by the persistence layer. In other words, I would define exceptions in the business layer and the persistence layer would interpret exceptions or other errors returned from the store and throw these specific, business-layer exceptions for each case that require special handling, such as a DuplicateKeyException or InvalidDataException. The
OptimisticConcurrencyException is an example of a move in this direction.