2010-03-04 54 views
21

Khi lưu thay đổi với SaveChanges trên ngữ cảnh dữ liệu có cách nào để xác định thực thể nào gây ra lỗi không? Ví dụ: đôi khi tôi sẽ quên chỉ định ngày cho trường ngày không có giá trị và nhận được lỗi "Phạm vi ngày không hợp lệ", nhưng tôi không nhận được thông tin về thực thể hoặc trường nào do thực thể đó gây ra (tôi thường có thể theo dõi nó theo cẩn thận đi qua tất cả các đồ vật của tôi, nhưng nó rất tốn thời gian). Theo dõi ngăn xếp là khá vô ích vì nó chỉ cho tôi thấy một lỗi tại cuộc gọi SaveChanges mà không có bất kỳ thông tin bổ sung nào về nơi chính xác nó xảy ra.Khung thực thể Lưu chi tiết lỗi

Lưu ý rằng tôi không tìm cách giải quyết bất kỳ vấn đề cụ thể nào tôi có bây giờ, tôi chỉ muốn biết nói chung nếu có cách nào để cho biết thực thể/trường nào đang gây ra sự cố.


mẫu nhanh của một stack trace làm ví dụ - trong trường hợp này một lỗi xảy ra bởi vì CreatedOn ngày đã không được đặt trên IAComment tổ chức nào, tuy nhiên nó không thể nói từ này lỗi/stack trace

[SqlTypeException: SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.] 
    System.Data.SqlTypes.SqlDateTime.FromTimeSpan(TimeSpan value) +2127345 
    System.Data.SqlTypes.SqlDateTime.FromDateTime(DateTime value) +232 
    System.Data.SqlClient.MetaType.FromDateTime(DateTime dateTime, Byte cb) +46 
    System.Data.SqlClient.TdsParser.WriteValue(Object value, MetaType type, Byte scale, Int32 actualLength, Int32 encodingByteSize, Int32 offset, TdsParserStateObject stateObj) +4997789 
    System.Data.SqlClient.TdsParser.TdsExecuteRPC(_SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc) +6248 
    System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) +987 
    System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +162 
    System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +32 
    System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +141 
    System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) +12 
    System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) +10 
    System.Data.Mapping.Update.Internal.DynamicUpdateCommand.Execute(UpdateTranslator translator, EntityConnection connection, Dictionary`2 identifierValues, List`1 generatedValues) +8084396 
    System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter) +267 

[UpdateException: An error occurred while updating the entries. See the inner exception for details.] 
    System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter) +389 
    System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache) +163 
    System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options) +609 
    IADAL.IAController.Save(IAHeader head) in C:\Projects\IA\IADAL\IAController.cs:61 
    IA.IAForm.saveForm(Boolean validate) in C:\Projects\IA\IA\IAForm.aspx.cs:198 
    IA.IAForm.advance_Click(Object sender, EventArgs e) in C:\Projects\IA\IA\IAForm.aspx.cs:287 
    System.Web.UI.WebControls.Button.OnClick(EventArgs e) +118 
    System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +112 
    System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10 
    System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13 
    System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +36 
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5019 

Trả lời

7

Một lựa chọn là để xử lý các ObjectContext.SavingChanges Event, mang đến cho bạn một cơ hội để thực hiện xác nhận vào đơn vị trước những thay đổi sẽ được lưu và thậm chí hủy lưu nếu cần thiết. Bằng cách này bạn có thể đảm bảo rằng bất kỳ thuộc tính không nullable nào được đặt trước khi cố gắng lưu thay đổi và tránh phải dựa vào xử lý ngoại lệ.

0

Tôi nghĩ tôi có thể thực hiện các cuộc gọi riêng biệt tới SaveChanges(). Đó thường là những gì tôi làm cho chính xác lý do này. Tôi có thể hỏi tại sao bạn đang lưu nhiều thực thể cùng một lúc? Nếu bạn phải làm vậy, tôi sẽ làm theo lời khuyên của người khác và xác thực các thực thể trước.

Hoặc có thể có cách tốt hơn để cấu trúc mã của bạn để trong các entiies hợp lệ thậm chí sẽ không được lưu để lưu. Có thể tách các thực thể của bạn, và sau đó chạy chúng thông qua một phương thức xác thực trước khi gắn chúng vào bối cảnh mới. Hy vọng rằng sẽ giúp!

1

Nếu tất cả những gì bạn cần làm là xem ngoại lệ bên trong thực tế, tất cả những gì bạn phải làm là đặt các thay đổi lưu bên trong khối thử, nắm bắt ngoại lệ và xem xét nó.

Tôi làm mọi lúc và nó hoạt động hoàn hảo.

0

Đây là mẫu của tôi về vài cờ: hoặc datetime = 0 hoặc chuỗi tràn:


public partial class MyContext  
{ 
    private static Dictionary> _fieldMaxLengths; 
    partial void OnContextCreated() 
    { 
     InitializeFieldMaxLength(); 
     SavingChanges -= BeforeSave; 
     SavingChanges += BeforeSave; 
    } 

    private void BeforeSave(object sender, EventArgs e) 
    { 
     StringOverflowCheck(sender); 
     DateTimeZeroCheck(sender); 
     CheckZeroPrimaryKey(sender); 
    } 

    private static void CheckZeroPrimaryKey(object sender) 
    { 
     var db = (CTAdminEntities)sender; 
     var modified = db.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified); 
     foreach (var entry in modified.Where(entry => !entry.IsRelationship)) 
     { 
      var entity = (EntityObject)entry.Entity; 
      Debug.Assert(entity != null); 
      var type = entity.GetType(); 
      foreach (var prop in type.GetProperties().Where(
       p => new[] { typeof(Int64), typeof(Int32), typeof(Int16) }.Contains(p.PropertyType))) 
      { 
       var attr = prop.GetCustomAttributes(typeof (EdmScalarPropertyAttribute), false); 
       if (attr.Length > 0 && ((EdmScalarPropertyAttribute) attr[0]).EntityKeyProperty) 
       { 
        long value = 0; 
        if (prop.PropertyType == typeof(Int64)) 
         value = (long) prop.GetValue(entity, null); 
        if (prop.PropertyType == typeof(Int32)) 
         value = (int) prop.GetValue(entity, null); 
        if (prop.PropertyType == typeof(Int16)) 
         value = (short) prop.GetValue(entity, null); 

        if (value == 0) 
         throw new Exception(string.Format("PK is 0 for Table {0} Key {1}", type, prop.Name)); 
        break; 
       } 
      } 
     } 
    } 

    private static void DateTimeZeroCheck(object sender) 
    { 
     var db = (CTAdminEntities)sender; 
     var modified = db.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified); 
     foreach (var entry in modified.Where(entry => !entry.IsRelationship)) 
     { 
      var entity = (EntityObject)entry.Entity; 
      Debug.Assert(entity != null); 
      var type = entity.GetType(); 
      foreach (var prop in type.GetProperties().Where(p => p.PropertyType == typeof(DateTime))) 
      { 
       var value = (DateTime)prop.GetValue(entity, null); 
       if (value == DateTime.MinValue) 
        throw new Exception(string.Format("Datetime2 is 0 Table {0} Column {1}", type, prop.Name)); 
      } 
      foreach (var prop in type.GetProperties().Where(
        p => p.PropertyType.IsGenericType && 
        p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable) && 
        p.PropertyType.GetGenericArguments()[0] == typeof(DateTime))) 
      { 
       var value = (DateTime?)prop.GetValue(entity, null); 
       if (value == DateTime.MinValue) 
        throw new Exception(string.Format("Datetime2 is 0 Table {0} Column {1}", type, prop.Name)); 
      } 
     } 
    } 

    private static void StringOverflowCheck(object sender) 
    { 
     var db = (CTAdminEntities)sender; 
     var modified = db.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified); 
     foreach (var entry in modified.Where(entry => !entry.IsRelationship)) 
     { 
      var entity = (EntityObject)entry.Entity; 
      Debug.Assert(entity != null); 
      var type = entity.GetType(); 
      var fieldMap = _fieldMaxLengths[type.Name]; 
      foreach (var key in fieldMap.Keys) 
      { 
       var value = (string)type.GetProperty(key).GetValue(entity, null); 
       if (value != null && value.Length > fieldMap[key]) 
        throw new Exception(string.Format("String Overflow on Table {0} Column {1}: {2} out of {3}", type, key, value.Length, fieldMap[key])); 
      } 
     } 
    } 

    private void InitializeFieldMaxLength() 
    { 
     if (_fieldMaxLengths != null) 
      return; 
     _fieldMaxLengths = new Dictionary>(); 

     var items = MetadataWorkspace.GetItems(DataSpace.CSpace); 
     Debug.Assert(items != null); 
     var tables = items.Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType); 

     foreach (EntityType table in tables) 
     { 
      var fieldsMap = new Dictionary(); 
      _fieldMaxLengths[table.Name] = fieldsMap; 
      var stringFields = table.Properties.Where(p => p.DeclaringType.Name == table.Name && p.TypeUsage.EdmType.Name == "String"); 
      foreach (var field in stringFields) 
      { 
       var value = field.TypeUsage.Facets["MaxLength"].Value; 
       if (value is Int32) 
        fieldsMap[field.Name] = Convert.ToInt32(value); 
       else 
        // unbounded 
        fieldsMap[field.Name] = Int32.MaxValue; 
      } 
     } 
    } 
} 
Các vấn đề liên quan