处理entity framework中的例外4

我需要一种方法来区分使用entity frameworkLINQ的SQLexception,例如,当我从DbUpdateException获得的是大量嵌套的内部exception和无用的长错误消息时,如何区分外键约束违规或唯一约束违规? 是否存在任何较低级别的exception,我可以执行类似“Catch FKException”的操作; 捕获“uniqueException”或类似的东西。

  try { //code } catch (System.Data.Entity.Validation.DbEntityValidationException e) { string rs = ""; foreach (var eve in e.EntityValidationErrors) { rs = string.Format("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", eve.Entry.Entity.GetType().Name, eve.Entry.State); Console.WriteLine(rs); foreach (var ve in eve.ValidationErrors) { rs += "
" + string.Format("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage); } } throw new Exception(rs); }

使用sql错误代码……

 catch (DbUpdateException ex) { var sqlex = ex.InnerException.InnerException as SqlException; if (sqlex != null) { switch (sqlex.Number) { case 547: throw new ExNoExisteUsuario("No existe usuario destino."); //FK exception case 2627: case 2601: throw new ExYaExisteConexion("Ya existe la conexion."); //primary key exception default: throw sqlex; //otra excepcion que no controlo. } } throw ex; } 

我为此写了几个实用方法:

 public static class DbUtils { ///  /// Takes a code block that updates database, runs it and catches db exceptions. If the caught /// exception is one of those that are ok to ignore (okToIgnoreChecks) then no /// exception is raised and result is returned. Otherwise an exception is rethrown. /// /// This function is intended to be run within an explicit transaction, ie: /// using (var transaction = db.Database.BeginTransaction()), which should be committed/rolledback afterwards. /// Otherwise, if you don't use a transaction discard the db context or in other words make this operation /// the only one that you run within implicit transaction. /// /// This function can wrap a single DB statement, but it's more efficient to wrap multiple statements /// so that locks are held for shorter period of time. /// If an exception occurs within a transaction and is caught by this function, all other changes /// will be still saved to DB on commit if transaction is used. ///  /// Any result returned by the code block /// Database connection ///  /// Code block to execute that updates DB. It's expected, but not critical that /// this code does not throw any other exceptions. Do not call SaveChanges() from the code block itself. Let this /// function do it for you. ///  ///  /// List of functions that will check if an exception can be ignored. ///  /// Returns number of rows affected in DB and result produced by the code block public static Tuple IgnoreErrors(DbContext context, Func dbCodeBlock, params Func[] okToIgnoreChecks) { var result = dbCodeBlock(); try { var rowsAffected = context.SaveChanges(); return Tuple.Create(rowsAffected, result); } catch (DbUpdateException e) { if (okToIgnoreChecks.Any(check => check(e))) return Tuple.Create(0, result); throw; } } public static bool IsDuplicateInsertError(DbUpdateException e) { return GetErrorCode(e) == 2601; } public static bool IsForeignKeyError(DbUpdateException e) { return GetErrorCode(e) == 547; } public static T UpdateEntity(DbContext context, T entity, Action entityModifications) where T : class { return EntityCrud(context, entity, (db, e) => { db.Attach(e); entityModifications(e); return e; }); } public static T DeleteEntity(DbContext context, T entity) where T : class { return EntityCrud(context, entity, (db, e) => db.Remove(e)); } public static T InsertEntity(DbContext context, T entity) where T : class { return EntityCrud(context, entity, (db, e) => db.Add(e)); } public static T EntityCrud(DbContext context, T entity, Func, T, T> crudAction) where T : class { return crudAction(context.Set(), entity); } } 

以下是如何使用它。 插入可能重复的行的示例:

 DbUtils.IgnoreErrors(_db, () => DbUtils.InsertEntity(_db, someEntity), DbUtils.IsDuplicateInsertError); 

不会抛出exception。

与前面的示例类似,但显式处理FK违例exception:

  try { var numInserted = DbUtils.IgnoreErrors(_db, () => DbUtils.InsertEntity(_db, someEntity), DbUtils.IsDuplicateInsertError).Item1; // no FK exception, but maybe unique index violation, safe // to keep going with transaction } catch (DbUpdateException e) { if (DbUtils.IsForeignKeyError(e)) { // you know what to do } throw; // rethrow other db errors } 

如果您有显式事务,最终可以调用commit transaction,否则已经在上下文中调用了save。