2013-09-27 170 views
5

Tôi cần một cách để phân biệt giữa các ngoại lệ SQL bằng cách sử dụng khung công tác LINQ, ví dụ cách phân biệt vi phạm ràng buộc khóa foreing hoặc vi phạm ràng buộc duy nhất khi tất cả tôi nhận được từ DbUpdateException là một tấn bên trong lồng nhau ngoại lệ và thông báo lỗi dài vô ích? Có bất kỳ ngoại lệ cấp thấp hơn mà tôi có thể làm một cái gì đó như "Catch FKException"; bắt "uniqueException" hoặc một cái gì đó tương tự.Xử lý ngoại lệ trong khung thực thể 4

+0

Thường thì các ngoại lệ bên trong sẽ chứa mã lỗi số, bạn đã thử tìm kiếm các mã lỗi đó chưa? Đăng một ví dụ về một ngoại lệ trong câu hỏi của bạn, hãy chắc chắn để làm nổi bật các văn bản và bấm vào nút '{}' để làm cho nó định dạng độc đáo. –

Trả lời

5

Sử dụng sql mã lỗi ...

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; 
        } 
11
  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 += "<br />" + string.Format("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage); 
        } 
       } 
       throw new Exception(rs); 
      } 
+4

Nếu bạn muốn thực sự loại dòng cuối cùng nên là 'ném ngoại lệ mới (rs, e) 'để người tiếp theo lên chuỗi có thể kiểm tra ngoại lệ bên trong và xem stacktrace và whatnot. (Ngoài ra ném một ngoại lệ tùy chỉnh thay vì một ngoại lệ 'chung 'sẽ được tốt đẹp quá) –

+0

Nhưng tôi thực sự cần phải phân biệt giữa chúng, tôi cần phải ném ngoại lệ khác nhau tùy thuộc vào loại lỗi cơ sở dữ liệu nó được. – user1777914

1

tôi đã viết vài phương pháp hữu ích cho việc này:

public static class DbUtils 
{ 
    /// <summary> 
    ///  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, i.e.: 
    ///  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. 
    /// </summary> 
    /// <typeparam name="T">Any result returned by the code block</typeparam> 
    /// <param name="context">Database connection</param> 
    /// <param name="dbCodeBlock"> 
    ///  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. 
    /// </param> 
    /// <param name="okToIgnoreChecks"> 
    ///  List of functions that will check if an exception can be ignored. 
    /// </param> 
    /// <returns>Returns number of rows affected in DB and result produced by the code block</returns> 
    public static Tuple<int, T> IgnoreErrors<T>(DbContext context, 
     Func<T> dbCodeBlock, params Func<DbUpdateException, bool>[] 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<T>(DbContext context, T entity, Action<T> entityModifications) 
     where T : class 
    { 
     return EntityCrud(context, entity, (db, e) => 
     { 
      db.Attach(e); 
      entityModifications(e); 
      return e; 
     }); 
    } 

    public static T DeleteEntity<T>(DbContext context, T entity) 
     where T : class 
    { 
     return EntityCrud(context, entity, (db, e) => db.Remove(e)); 
    } 

    public static T InsertEntity<T>(DbContext context, T entity) 
     where T : class 
    { 
     return EntityCrud(context, entity, (db, e) => db.Add(e)); 
    } 

    public static T EntityCrud<T>(DbContext context, T entity, Func<DbSet<T>, T, T> crudAction) 
     where T : class 
    { 
     return crudAction(context.Set<T>(), entity); 
    } 
} 

Đây là cách bạn có thể sử dụng nó. Ví dụ về việc chèn hàng có khả năng trùng lặp:

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

Không có ngoại lệ.

Tương tự như ví dụ trước, nhưng xử lý vi phạm FK ngoại lệ một cách rõ ràng:

 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 
     } 

Cuối cùng bạn có thể gọi cam kết giao dịch nếu bạn có một giao dịch rõ ràng, nếu không tiết kiệm đã được gọi vào ngữ cảnh rồi.