2010-03-04 3 views
21

Lors de l'enregistrement des modifications avec SaveChanges sur un contexte de données, existe-t-il un moyen de déterminer quelle Entité provoque une erreur? Par exemple, j'oublie parfois d'attribuer une date à un champ de date non nul et d'obtenir une erreur "Invalid Date Range", mais je ne reçois aucune information sur l'entité ou le champ par lequel elle est générée (je peux généralement la localiser par passer minutieusement tous mes objets, mais cela prend beaucoup de temps). Stack trace est assez inutile car il me montre seulement une erreur à l'appel SaveChanges sans aucune information supplémentaire sur l'endroit exact où il est arrivé.Détails de l'erreur Entity Framework SaveChanges

Notez que je ne cherche pas à résoudre un problème particulier que j'ai maintenant, je voudrais juste savoir en général s'il y a un moyen de dire quelle entité/champ cause un problème.


échantillon rapide d'une trace de la pile comme un exemple - dans ce cas, une erreur est survenue parce que la date CreatedOn n'a pas été mis sur l 'entité IAComment, mais il est impossible de dire de cette erreur/pile 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 

Répondre

7

Une option consiste à gérer le ObjectContext.SavingChanges Event, ce qui vous donne une chance d'effectuer la validation des entités avant que les modifications sont enregistrées et même annuler la sauvegarde si nécessaire. De cette façon, vous pouvez vous assurer que toutes les propriétés non-nullables sont définies avant d'essayer d'enregistrer les modifications, et évitez de devoir compter sur la gestion des exceptions.

0

Je pense que je pourrais faire des appels séparés à SaveChanges(). C'est habituellement ce que je fais pour exactement cette raison. Puis-je vous demander pourquoi vous sauvegardez plusieurs entités à la fois? Si vous le deviez, je suivrais le conseil de l'autre et validerais les entités à l'avance.

Ou peut-être existe-t-il un meilleur moyen de structurer votre code de façon à ce qu'il ne soit même pas tenté d'enregistrer des codes dans les entiers valides. Détachez peut-être vos entités, puis exécutez-les via une méthode de validation avant de les attacher au nouveau contexte. J'espère que cela pourra aider!

1

Si tout ce que vous avez à faire est de voir l'exception interne réelle à la place, tout ce que vous avez à faire est de mettre les changements de sauvegarde dans un bloc try, attraper l'exception et le regarder.

Je le fais tout le temps et ça fonctionne parfaitement.

0

Voici mon échantillon de dames de couple: soit datetime = 0 ou chaîne: déversoirs


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; 
      } 
     } 
    } 
} 
Questions connexes