处理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。
- 无法在电脑上打开窗口服务’。’ 在窗口应用程序中
- Windows Phone 7 – 捕获屏幕
- 在Ninject 3.0中使用默认参数值
- WebBrowser快捷方式无法在PowerPoint加载项中运行…但WebBrowserShortcutsEnabled为true
- 由Windows.Security.Cryptography.CryptographicBuffer中的方法生成的IBuffer对象是否具有安全function?
- 将C ++ string / wchar_t *转换为C#字符串?
- 如何在c ++和c#中实现vtables?
- Windows服务无法启动(错误1053)
- 在Gtk中,是否有可能使小部件淡入淡出?