Échec de la Validation pour une ou plusieurs entités lors de l'enregistrement de modifications à la base de données SQL Server en utilisant le cadre D'Entity

je veux sauver mon édition à la base de données et j'utilise le code de cadre D'entité-premier en ASP.NET MVC 3 / C# mais je reçois des erreurs. Dans ma classe D'événements, j'ai des types de données DateTime et TimeSpan, mais dans ma base de données, j'ai la Date et l'heure respectivement. Serait-ce la raison? Comment puis-je lancer vers le type de données approprié dans le code avant de sauvegarder les modifications dans la base de données.

public class Event
{
    public int EventId { get; set; }
    public int CategoryId { get; set; }
    public int PlaceId { get; set; }
    public string Title { get; set; }
    public decimal Price { get; set; }
    public DateTime EventDate { get; set; }
    public TimeSpan StartTime { get; set; }
    public TimeSpan EndTime { get; set; }
    public string Description { get; set; }
    public string EventPlaceUrl { get; set; }
    public Category Category { get; set; }
    public Place Place { get; set; }
}

méthode dans le contrôleur > > > > problème à storebd.SaveChanges ();

// POST: /EventManager/Edit/386        
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
    var theEvent = storeDB.Events.Find(id);

    if (TryUpdateModel(theEvent))
    {
        storeDB.SaveChanges();
        return RedirectToAction("Index");
    }
    else
    {
        ViewBag.Categories = storeDB.Categories.OrderBy(g => g.Name).ToList();
        ViewBag.Places = storeDB.Places.OrderBy(a => a.Name).ToList();
        return View(theEvent);
    }
}

avec

public class EventCalendarEntities : DbContext
{
    public DbSet<Event> Events { get; set; }
    public DbSet<Category> Categories { get; set; }
    public DbSet<Place> Places { get; set; } 
}

SQL Server 2008 R2 Database /T-SQL

EventDate (Datatype = date)  
StartTime (Datatype = time)  
EndTime (Datatype = time)  

Formulaire Http

EventDate (Datatype = DateTime) e.g. 4/8/2011 12:00:00 AM  
StartTime (Datatype = Timespan/time not sure) e.g. 08:30:00  
EndTime (Datatype = Timespan/time not sure) e.g. 09:00:00  

erreur de serveur dans L'Application'/'.

Échec de la Validation

pour une ou plusieurs entités. Voir la propriété "EntityValidationErrors" pour plus de détails.

Description: Une exception non gérée s'est produite pendant l'exécution de la demande web actuelle. Merci examinez la trace de la pile pour plus d'informations sur l'erreur et son origine dans le code.

Détails De L'Exception: Système.Données.Entité.Validation.DbEntityValidationException: la Validation a échoué pour une ou plusieurs entités. Voir la propriété "EntityValidationErrors" pour plus de détails.

Source D'Erreur:

Line 75:             if (TryUpdateModel(theEvent))
Line 76:             {
Line 77:                 storeDB.SaveChanges();
Line 78:                 return RedirectToAction("Index");
Line 79:             }

Fichier Source: C:sepMvcEventCalendarMvcEventCalendarControllersEventManagerController.ligne cs: 77

Trace De La Pile:

[DbEntityValidationException: la Validation a échoué pour une ou plusieurs entités. Voir la propriété "EntityValidationErrors" pour plus de détails.]

327
demandé sur HonourCode 2011-03-23 06:18:45

16 réponses

vous pouvez extraire toutes les informations de la DbEntityValidationException avec le code suivant (vous devez ajouter les espaces de noms: System.Data.Entity.Validation et System.Diagnostics à votre using liste):

catch (DbEntityValidationException dbEx)
{
    foreach (var validationErrors in dbEx.EntityValidationErrors)
    {
        foreach (var validationError in validationErrors.ValidationErrors)
        {
            Trace.TraceInformation("Property: {0} Error: {1}", 
                                    validationError.PropertyName, 
                                    validationError.ErrorMessage);
        }
    }
}
831
répondu Praveen Prasad 2015-07-08 18:28:10

aucun changement de code requis:

pendant que vous êtes en mode débogage dans le bloc catch {...} ouvrez la fenêtre" QuickWatch " ( Ctrl + Alt + Q ) et collez là:

((System.Data.Entity.Validation.DbEntityValidationException)ex).EntityValidationErrors

ou:

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors

si vous n'êtes pas dans un try/catch ou n'avez pas accès à l'objet exception.

cela vous permettra de creuser dans l'arbre ValidationErrors . C'est le moyen le plus facile que j'ai trouvé pour avoir un aperçu instantané de ces erreurs.

247
répondu GONeale 2016-03-14 23:29:05

dans le cas où vous avez des classes avec les mêmes noms de propriétés, voici une petite extension à la réponse de Praveen:

 catch (DbEntityValidationException dbEx)
 {
    foreach (var validationErrors in dbEx.EntityValidationErrors)
    {
       foreach (var validationError in validationErrors.ValidationErrors)
       {
          Trace.TraceInformation(
                "Class: {0}, Property: {1}, Error: {2}",
                validationErrors.Entry.Entity.GetType().FullName,
                validationError.PropertyName,
                validationError.ErrorMessage);
       }
    }
 }
36
répondu Tony 2015-07-08 17:54:51

pour améliorer à la fois Praveen et Tony, j'utilise un contrôleur:

public partial class MyDatabaseEntities : DbContext
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException dbEx)
        {
            foreach (var validationErrors in dbEx.EntityValidationErrors)
            {
                foreach (var validationError in validationErrors.ValidationErrors)
                {
                    Trace.TraceInformation("Class: {0}, Property: {1}, Error: {2}",
                        validationErrors.Entry.Entity.GetType().FullName,
                        validationError.PropertyName,
                        validationError.ErrorMessage);
                }
            }

            throw;  // You can also choose to handle the exception here...
        }
    }
}
22
répondu Bolt Thunder 2012-08-09 14:36:00

Cette mise en œuvre envelopper entité exception à l'exception du détail du texte. Il manipule DbEntityValidationException , DbUpdateException , datetime2 les erreurs de gamme (MS SQL), et inclure la clé de l'entité invalide dans le message (utile quand savind beaucoup d'entités à un appel SaveChanges ).

premièrement, remplacer SaveChanges dans la classe DbContext:

public class AppDbContext : DbContext
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException dbEntityValidationException)
        {
            throw ExceptionHelper.CreateFromEntityValidation(dbEntityValidationException);
        }
        catch (DbUpdateException dbUpdateException)
        {
            throw ExceptionHelper.CreateFromDbUpdateException(dbUpdateException);
        }
    }   

    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken)
    {
        try
        {
            return await base.SaveChangesAsync(cancellationToken);
        }
        catch (DbEntityValidationException dbEntityValidationException)
        {
            throw ExceptionHelper.CreateFromEntityValidation(dbEntityValidationException);
        }
        catch (DbUpdateException dbUpdateException)
        {
            throw ExceptionHelper.CreateFromDbUpdateException(dbUpdateException);
        }
    }

ExceptionHelper class:

public class ExceptionHelper
{
    public static Exception CreateFromEntityValidation(DbEntityValidationException ex)
    {
        return new Exception(GetDbEntityValidationMessage(ex), ex);
    }

    public static string GetDbEntityValidationMessage(DbEntityValidationException ex)
    {
        // Retrieve the error messages as a list of strings.
        var errorMessages = ex.EntityValidationErrors
            .SelectMany(x => x.ValidationErrors)
            .Select(x => x.ErrorMessage);

        // Join the list to a single string.
        var fullErrorMessage = string.Join("; ", errorMessages);

        // Combine the original exception message with the new one.
        var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);
        return exceptionMessage;
    }

    public static IEnumerable<Exception> GetInners(Exception ex)
    {
        for (Exception e = ex; e != null; e = e.InnerException)
            yield return e;
    }

    public static Exception CreateFromDbUpdateException(DbUpdateException dbUpdateException)
    {
        var inner = GetInners(dbUpdateException).Last();
        string message = "";
        int i = 1;
        foreach (var entry in dbUpdateException.Entries)
        {
            var entry1 = entry;
            var obj = entry1.CurrentValues.ToObject();
            var type = obj.GetType();
            var propertyNames = entry1.CurrentValues.PropertyNames.Where(x => inner.Message.Contains(x)).ToList();
            // check MS SQL datetime2 error
            if (inner.Message.Contains("datetime2"))
            {
                var propertyNames2 = from x in type.GetProperties()
                                        where x.PropertyType == typeof(DateTime) ||
                                            x.PropertyType == typeof(DateTime?)
                                        select x.Name;
                propertyNames.AddRange(propertyNames2);
            }

            message += "Entry " + i++ + " " + type.Name + ": " + string.Join("; ", propertyNames.Select(x =>
                string.Format("'{0}' = '{1}'", x, entry1.CurrentValues[x])));
        }
        return new Exception(message, dbUpdateException);
    }
}
6
répondu Sel 2017-03-21 16:00:40

ce code a aidé à trouver mon problème lorsque j'ai eu des problèmes avec mes erreurs de VAlidation D'entité. Il m'a dit le problème exact avec ma définition D'entité. Essayez de suivre le code où vous devez couvrir storebd.SaveChanges(); dans la suite essayer bloc catch.

  try
{
         if (TryUpdateModel(theEvent))
         {
             storeDB.SaveChanges();
             return RedirectToAction("Index");
         }
}
catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
{
    Exception raise = dbEx;
    foreach (var validationErrors in dbEx.EntityValidationErrors)
    {
        foreach (var validationError in validationErrors.ValidationErrors)
        {
            string message = string.Format("{0}:{1}", 
                validationErrors.Entry.Entity.ToString(),
                validationError.ErrorMessage);
            // raise a new exception nesting
            // the current instance as InnerException
            raise = new InvalidOperationException(message, raise);
        }
    }
    throw raise;
}
5
répondu Рахул Маквана 2016-04-10 00:50:36

j'ai eu cette erreur aujourd'hui et je n'ai pas pu le résoudre pendant un moment, mais j'ai réalisé que c'était après avoir ajouté quelques RequireAttribute à mes modèles et que certaines données de développement de graine n'étaient pas peuplant tous les champs requis.

Donc juste une note que si vous obtenez cette erreur lors de la mise à jour de la base de données par une sorte de stratégie d'initialisation comme DropCreateDatabaseIfModelChanges alors vous devez vous assurer que vos données de graine remplissent et satisfont des données de modèle attributs de validation .

je sais que c'est légèrement différent du problème dans la question, mais c'est une question populaire donc j'ai pensé que je voudrais ajouter un peu plus à la réponse pour les autres ayant le même problème que moi.

Espérons que cela aide les autres :)

4
répondu dan richardson 2012-12-13 10:51:08

je pense que l'ajout d'essayer / attraper pour chaque opération SaveChanges() n'est pas une bonne pratique, il est préférable de centraliser ceci:

ajouter cette classe à la classe principale DbContext :

public override int SaveChanges()
{
    try
    {
        return base.SaveChanges();
    }
    catch (DbEntityValidationException ex)
    {
        string errorMessages = string.Join("; ", ex.EntityValidationErrors.SelectMany(x => x.ValidationErrors).Select(x => x.ErrorMessage));
        throw new DbEntityValidationException(errorMessages);
    }
}

cela écrasera la méthode SaveChanges() de votre contexte et vous obtiendrez une liste séparée par des virgules contenant toutes les erreurs de validation de l'entité.

cela peut également être amélioré, pour enregistrer les erreurs dans la production env, au lieu de jeter simplement un erreur.

j'espère que c'est utile.

4
répondu Chtiwi Malek 2015-04-18 18:45:21

voici une extension de L'extension de Tony... :- )

Pour Entity Framework 4.x, si vous voulez obtenir le nom et la valeur du champ clé pour que vous sachiez quelle instance de l'entité (enregistrement DB) a le problème, vous pouvez ajouter ce qui suit. Cela permet d'accéder aux membres les plus puissants de la classe ObjectContext à partir de votre objet DbContext.

// Get the key field name & value.
// This assumes your DbContext object is "_context", and that it is a single part key.
var e = ((IObjectContextAdapter)_context).ObjectContext.ObjectStateManager.GetObjectStateEntry(validationErrors.Entry.Entity);
string key = e.EntityKey.EntityKeyValues[0].Key;
string val = e.EntityKey.EntityKeyValues[0].Value;
3
répondu Martin_ATS 2012-04-14 09:38:06

Je n'aime pas les exceptions J'ai enregistré les OnSaveChanges et j'ai ce

var validationErrors = model.GetValidationErrors();

var h = validationErrors.SelectMany(x => x.ValidationErrors
                                          .Select(f => "Entity: " 
                                                      +(x.Entry.Entity) 
                                                      + " : " + f.PropertyName 
                                                      + "->" + f.ErrorMessage));
3
répondu Mickey Perlstein 2015-12-14 18:38:52

Cette erreur se produit également lorsque vous essayez d'enregistrer une entité qui a des erreurs de validation. Un bon moyen de provoquer cela est d'oublier de vérifier ModelState.IsValid avant de sauvegarder dans votre base de données.

2
répondu laylarenee 2013-11-20 19:24:30

assurez-vous que si vous avez nvarchar(50)dans DB row vous n'essayez pas d'y insérer plus de 50 caractères. Erreur stupide mais ça m'a pris 3 heures pour le découvrir.

2
répondu user4030144 2014-09-11 08:52:47

cela pourrait être dû au nombre maximum de caractères permis pour une colonne spécifique, comme dans sql un champ pourrait avoir le Type de données suivant nvarchar(5) mais le nombre de caractères entrés par l'utilisateur est plus que le spécifié, donc l'erreur se produit.

1
répondu lokopi 2016-06-01 08:00:23

j'ai fait face à la même question Il ya quelques jours lors de la mise à jour de la base de données. Dans mon cas, il y a eu peu de nouvelles colonnes non nulles ajoutées pour la maintenance qui n'ont pas été fournies dans le code qui est à l'origine de l'exception. Je trouve ces champs et ai fourni des valeurs pour eux et son résolu.

1
répondu JM Kumawat 2017-02-05 03:40:17

Merci pour vos réponses, ça m'aide beaucoup. comme je code dans Vb.Net, ce code de Vb.Net

Try
   Return MyBase.SaveChanges()
Catch dbEx As Validation.DbEntityValidationException
   For Each [error] In From validationErrors In dbEx.EntityValidationErrors
                       From validationError In validationErrors.ValidationErrors
                       Select New With { .PropertyName = validationError.PropertyName,
                                         .ErrorMessage = validationError.ErrorMessage,
                                         .ClassFullName = validationErrors.Entry.Entity
                                                                    .GetType().FullName}

        Diagnostics.Trace.TraceInformation("Class: {0}, Property: {1}, Error: {2}",
                                           [error].ClassFullName,
                                           [error].PropertyName,
                                           [error].ErrorMessage)
   Next
   Throw
End Try
0
répondu Exatex 2015-12-14 18:37:58

il peut être causé par une propriété qui n'est pas peuplée par model.. au lieu de cela, il est peuplé par Controller.. ce qui peut provoquer cette erreur.. la solution à cela est d'attribuer la propriété avant d'appliquer ModelState de validation. et cette seconde Hypothèse . vous avez déjà des Données dans votre Base de données et en essayant de le mettre à jour, mais aujourd'hui, l'extraction.

0
répondu Muhammad Mustafa 2016-04-13 19:30:46