diff --git a/src/Spring/Spring.Data/Data/Common/ErrorCodes.cs b/src/Spring/Spring.Data/Data/Common/ErrorCodes.cs index 44363ac8..29e30c40 100644 --- a/src/Spring/Spring.Data/Data/Common/ErrorCodes.cs +++ b/src/Spring/Spring.Data/Data/Common/ErrorCodes.cs @@ -39,23 +39,25 @@ namespace Spring.Data.Common public class ErrorCodes { #region Fields - private String[] databaseProductNames; + private string[] databaseProductNames; - private String[] badSqlGrammarCodes = new String[0]; + private string[] badSqlGrammarCodes = new String[0]; - private String[] invalidResultSetAccessCodes = new String[0]; + private string[] invalidResultSetAccessCodes = new String[0]; - private String[] dataAccessResourceFailureCodes = new String[0]; + private string[] dataAccessResourceFailureCodes = new String[0]; - private String[] permissionDeniedCodes = new String[0]; + private string[] permissionDeniedCodes = new String[0]; - private String[] dataIntegrityViolationCodes = new String[0]; + private string[] dataIntegrityViolationCodes = new String[0]; - private String[] cannotAcquireLockCodes = new String[0]; + private string[] cannotAcquireLockCodes = new String[0]; - private String[] deadlockLoserCodes = new String[0]; + private string[] deadlockLoserCodes = new String[0]; - private String[] cannotSerializeTransactionCodes = new String[0]; + private string[] cannotSerializeTransactionCodes = new String[0]; + + private string[] duplicateKeyCodes = new string[0]; // CustomErrorCodesTranslation[] customTranslations; #endregion @@ -144,13 +146,14 @@ namespace Spring.Data.Common get { return cannotSerializeTransactionCodes; } set { cannotSerializeTransactionCodes = value; } } - - #endregion - #region Methods + public string[] DuplicateKeyCodes + { + get { return duplicateKeyCodes; } + set { duplicateKeyCodes = value; } + } #endregion - } } \ No newline at end of file diff --git a/src/Spring/Spring.Data/Data/DuplicateKeyException.cs b/src/Spring/Spring.Data/Data/DuplicateKeyException.cs new file mode 100644 index 00000000..1b4f92c3 --- /dev/null +++ b/src/Spring/Spring.Data/Data/DuplicateKeyException.cs @@ -0,0 +1,141 @@ +#region License + +/* + * Copyright © 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +#region Imports + +using System; +using System.Runtime.Serialization; +using Spring.Dao; + +#endregion + +namespace Spring.Data +{ + /// + /// Exception thrown when an attempt to insert or update data + /// results in violation of an primary key or unique constraint. + /// Note that this is not necessarily a purely relational concept; + /// unique primary keys are required by most database types. + /// + /// Thomas Risberg + /// Mark Pollack (.NET) + [Serializable] + public class DuplicateKeyException : DataIntegrityViolationException + { + #region Fields + + /// + /// SQL that led to the problem + /// + private string sql; + + #endregion + + #region Constructor (s) + /// + /// Initializes a new instance of the class. + /// + public DuplicateKeyException() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + public DuplicateKeyException(string message): base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// A message about the exception. + /// The inner exception. + public DuplicateKeyException(string message, Exception inner): base(message, inner) + { + } + + + /// + /// Initializes a new instance of the class. + /// + /// name of the current task. + /// The offending SQL statment + /// The root cause. + public DuplicateKeyException(string task, String sql, Exception ex) : base(task + "; Duplicate key for SQL [" + sql + "]; " + ex.Message, ex) + { + this.sql = sql; + } + /// + /// Creates a new instance of the + /// class. + /// + /// + /// The + /// that holds the serialized object data about the exception being thrown. + /// + /// + /// The + /// that contains contextual information about the source or destination. + /// + protected DuplicateKeyException(SerializationInfo info, StreamingContext context) : base(info, context) { } + + + + #endregion + + #region Properties + + /// + /// Gets the SQL that caused the exception + /// + /// The SQL that caused the exception. + public string Sql + { + get + { + return sql; + } + } + #endregion + + #region Methods + + #endregion + + #region ISerializable Members + + /// + /// When overridden in a derived class, sets the + /// with information about the exception. + /// + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. + /// The parameter is a null reference ( in Visual Basic). + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue( "sql", sql ); + base.GetObjectData( info, context ); + } + + #endregion + } +} diff --git a/src/Spring/Spring.Data/Data/Support/ErrorCodeExceptionTranslator.cs b/src/Spring/Spring.Data/Data/Support/ErrorCodeExceptionTranslator.cs index 01d3b4f4..f417a87c 100644 --- a/src/Spring/Spring.Data/Data/Support/ErrorCodeExceptionTranslator.cs +++ b/src/Spring/Spring.Data/Data/Support/ErrorCodeExceptionTranslator.cs @@ -141,7 +141,8 @@ namespace Spring.Data.Support #endregion - /// + + /// /// Translate the given into a generic data access exception. /// /// A readable string describing the task being attempted. @@ -152,19 +153,61 @@ namespace Spring.Data.Support /// /// A appropriate for the supplied /// . - /// - public virtual DataAccessException Translate(string task, string sql, Exception exception) + /// + public virtual DataAccessException Translate(string task, string sql, Exception exception) + { + if (task == null) + { + task = ""; + } + if (sql == null) + { + sql = ""; + } + string errorCode = ExtractErrorCode(exception); + + // First, try custom translation from overridden method. + DataAccessException dex = DoTranslate(task, sql, errorCode, exception); + if (dex != null) + { + // Specific exception match found. + return dex; + } + // Looking for a fallback... + if (log.IsDebugEnabled) + { + log.Debug("Unable to translate exception eith errorCode '" + errorCode + "', will use the fallback translator"); + } + IAdoExceptionTranslator fallback = FallbackTranslator; + if (fallback != null) + { + return FallbackTranslator.Translate(task, sql, exception); + } + // We couldn't identify it more precisely. + return new UncategorizedAdoException(task, sql, errorCode, exception); + + + } + + /// + /// Template method for actually translating the given exception. + /// given into a generic data access exception. + /// + /// A readable string describing the task being attempted. + /// The SQL query or update that caused the problem. May be null. + /// The error code. + /// The encountered by the ADO.NET implementation. + /// + /// A appropriate for the supplied + /// . + /// + /// + /// The passed-in arguments will have been pre-checked. furthermore, this method is allowed to + /// return null to indicate that no exception match has been found and that + /// fallback translation should kick in. + /// + protected virtual DataAccessException DoTranslate(string task, string sql, string errorCode, Exception exception) { - if (task == null) - { - task = ""; - } - if (sql == null) - { - sql = ""; - } - string errorCode = ExtractErrorCode(exception); - // First, try custom translation from overridden method. DataAccessException dex = TranslateException(task, sql, errorCode, exception); if (dex != null) @@ -187,6 +230,11 @@ namespace Spring.Data.Support { LogTranslation(task, sql, errorCode, exception, false); return new InvalidResultSetAccessException(task, sql, exception); + } + else if (Array.IndexOf(errorCodes.DuplicateKeyCodes, errorCode) >= 0) + { + LogTranslation(task, sql, errorCode, exception, false); + return new DuplicateKeyException(task, sql, exception); } else if (Array.IndexOf(errorCodes.DataAccessResourceFailureCodes, errorCode) >= 0) { @@ -220,11 +268,7 @@ namespace Spring.Data.Support } } } - if (log.IsDebugEnabled) - { - log.Debug("Unable to translate exception eith errorCode '" + errorCode + "', will use the fallback translator"); - } - return fallbackTranslator.Translate(task, sql, exception); + return null; } /// diff --git a/src/Spring/Spring.Data/Spring.Data.2005.csproj b/src/Spring/Spring.Data/Spring.Data.2005.csproj index 20050270..3dc5317f 100644 --- a/src/Spring/Spring.Data/Spring.Data.2005.csproj +++ b/src/Spring/Spring.Data/Spring.Data.2005.csproj @@ -39,7 +39,7 @@ false false false - false + true 4 full prompt @@ -147,6 +147,7 @@ + diff --git a/src/Spring/Spring.Data/Spring.Data.2008.csproj b/src/Spring/Spring.Data/Spring.Data.2008.csproj index 55e4b3f8..b753c6a8 100644 --- a/src/Spring/Spring.Data/Spring.Data.2008.csproj +++ b/src/Spring/Spring.Data/Spring.Data.2008.csproj @@ -1,7 +1,7 @@  Local - 9.0.21022 + 9.0.30729 2.0 {AE00E5AB-C39A-436F-86D2-33BFE33E2E40} Debug @@ -155,6 +155,7 @@ +