wake-up-neo.net

DbEntityValidationException - Wie kann ich leicht feststellen, was den Fehler verursacht hat?

Ich habe ein Projekt, das Entity Framework verwendet. Beim Aufruf von SaveChanges für meinen DbContext erhalte ich die folgende Ausnahme:

System.Data.Entity.Validation.DbEntityValidationException: Überprüfung für eine oder mehrere Entitäten fehlgeschlagen. Siehe 'EntityValidationErrors'-Eigenschaft für mehr Details.

Das ist alles in Ordnung, aber ich möchte nicht jedes Mal, wenn diese Ausnahme auftritt, einen Debugger anhängen. Darüber hinaus kann ich in Produktionsumgebungen nicht ohne weiteres einen Debugger anhängen, sodass ich mich sehr bemühen muss, diese Fehler zu reproduzieren. 

Wie kann ich die Details innerhalb von DbEntityValidationException sehen?

205

Die einfachste Lösung besteht darin, SaveChanges in Ihrer Entitätsklasse zu überschreiben. Sie können die DbEntityValidationException abfangen, die tatsächlichen Fehler auspacken und eine neue DbEntityValidationException mit der verbesserten Nachricht erstellen.

  1. Erstellen Sie eine Teilklasse neben Ihrer Datei "SomethingSomething.Context.cs".
  2. Verwenden Sie den Code am Ende dieses Beitrags. 
  3. Das ist es. Ihre Implementierung verwendet automatisch die überschriebenen SaveChanges ohne Refactor-Arbeit.

Ihre Ausnahmemeldung sieht jetzt so aus:

System.Data.Entity.Validation.DbEntityValidationException: Überprüfung für eine oder mehrere Entitäten fehlgeschlagen. Siehe 'EntityValidationErrors'-Eigenschaft für mehr Details. Die Validierungsfehler sind: Das Feld PhoneNumber muss ein String- oder Array-Typ mit einer maximalen Länge von '12' sein; Das Das Feld Nachname ist erforderlich.

Sie können die überschriebenen SaveChanges in jeder Klasse ablegen, die von DbContext erbt:

public partial class SomethingSomethingEntities
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (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);
    
            // Throw a new DbEntityValidationException with the improved exception message.
            throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
        }
    }
}

Die Variable DbEntityValidationException enthält auch die Entitäten, die die Validierungsfehler verursacht haben. Wenn Sie noch mehr Informationen benötigen, können Sie den obigen Code ändern, um Informationen zu diesen Entitäten auszugeben.

Siehe auch: http://devillers.nl/improving-dbentityvalidationexception/

413

Wie Martin angedeutet hat, enthält DbEntityValidationResult weitere Informationen. Ich fand es nützlich, in jeder Nachricht sowohl meinen POCO-Klassennamen als auch den Eigenschaftennamen zu erhalten, und wollte vermeiden, für all meine [Required]-Tags benutzerdefinierte ErrorMessage-Attribute schreiben zu müssen.

Der folgende Tweak to Martin-Code hat sich für mich um diese Details gekümmert:

// Retrieve the error messages as a list of strings.
List<string> errorMessages = new List<string>();
foreach (DbEntityValidationResult validationResult in ex.EntityValidationErrors)
{
    string entityName = validationResult.Entry.Entity.GetType().Name;
    foreach (DbValidationError error in validationResult.ValidationErrors)
    {
        errorMessages.Add(entityName + "." + error.PropertyName + ": " + error.ErrorMessage);
    }
}
44
Eric Hirst

Fügen Sie dem Watch-Fenster den folgenden Watch-Ausdruck hinzu, um die EntityValidationErrors-Sammlung anzuzeigen.

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

Ich benutze Visual Studio 2013

41
Shehab Fawzy

Öffnen Sie im Debug-Modus des Blocks catch {...} das Fenster "QuickWatch" (ctrl+alt+q) und dort einfügen:

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

Auf diese Weise können Sie einen Drilldown in den Baum ValidationErrors durchführen. Es ist der einfachste Weg, einen sofortigen Einblick in diese Fehler zu bekommen.

Für Benutzer von Visual 2012+, denen nur der erste Fehler wichtig ist und die möglicherweise keinen catch -Block haben, können Sie sogar Folgendes tun:

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors.First().ValidationErrors.First().ErrorMessage
13
GONeale

So finden Sie schnell eine aussagekräftige Fehlermeldung, indem Sie den Fehler während des Debugging überprüfen:

  • Fügen Sie eine kurze Übersicht hinzu für:

    ((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
    
  • Drilldown in EntityValidationErrors wie folgt:

    (Sammlungselement, z. B. [0])> ValidationErrors> (Sammlungselement, z. B. [0])> ErrorMessage

9
Chris Halcrow

Tatsächlich ist dies nur ein Validierungsproblem. EF überprüft zuerst die Entitätseigenschaften, bevor Änderungen an der Datenbank vorgenommen werden. __ EF prüft also, ob der Wert der Eigenschaft außerhalb des Bereichs liegt, wie beim Entwerfen der Tabelle. Table_Column_UserName ist varchar (20). In EF haben Sie jedoch einen Wert eingegeben, der länger als 20 .__ ist. In anderen Fällen müssen Sie, wenn die Spalte keinen NULL-Wert zulässt, _ einen Wert festlegen auf die nicht-null-Spalte, egal, ob Sie die Änderung daran vornehmen werden ... Ich persönlich mag die Antwort von Leniel Macaferi. Es kann Ihnen die Details der Validierungsprobleme zeigen

5
Calvin

Ich denke, "Die tatsächlichen Validierungsfehler" können vertrauliche Informationen enthalten. Dies könnte der Grund sein, warum Microsoft sie an einem anderen Ort platziert hat (Eigenschaften). Die hier markierte Lösung ist praktisch, sollte aber mit Vorsicht genommen werden.

Ich würde es vorziehen, eine Erweiterungsmethode zu erstellen. Weitere Gründe dafür: 

  • Behalten Sie die ursprüngliche Stapelverfolgung bei
  • Befolgen Sie das Open/Closed-Prinzip (dh: Ich kann verschiedene Meldungen für verschiedene Arten von Protokollen verwenden) 
  • In Produktionsumgebungen könnte es andere Stellen geben (z. B .: other dbcontext), an denen eine DbEntityValidationException ausgelöst werden kann.
3
Luis Toapanta

Für Azure-Funktionen verwenden wir diese einfache Erweiterung für Microsoft.Extensions.Logging.ILogger

public static class LoggerExtensions
{
    public static void Error(this ILogger logger, string message, Exception exception)
    {
        if (exception is DbEntityValidationException dbException)
        {
            message += "\nValidation Errors: ";
            foreach (var error in dbException.EntityValidationErrors.SelectMany(entity => entity.ValidationErrors))
            {
                message += $"\n * Field name: {error.PropertyName}, Error message: {error.ErrorMessage}";
            }
        }

        logger.LogError(default(EventId), exception, message);
    }
}

und Beispielnutzung: 

try
{
    do something with request and EF
}
catch (Exception e)
{
    log.Error($"Failed to create customer due to an exception: {e.Message}", e);
    return await StringResponseUtil.CreateResponse(HttpStatusCode.InternalServerError, e.Message);
}
0
Juri

Verwenden Sie try block in Ihrem Code wie

try
{
    // Your code...
    // Could also be before try if you know the exception occurs in SaveChanges

    context.SaveChanges();
}
catch (DbEntityValidationException e)
{
    foreach (var eve in e.EntityValidationErrors)
    {
        Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
            eve.Entry.Entity.GetType().Name, eve.Entry.State);
        foreach (var ve in eve.ValidationErrors)
        {
            Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
                ve.PropertyName, ve.ErrorMessage);
        }
    }
    throw;
}

Sie können die Details auch hier überprüfen

  1. http://mattrandle.me/viewing-entityvalidationerrors-in-visual-studio/

  2. Überprüfung für eine oder mehrere Entitäten fehlgeschlagen. Siehe 'EntityValidationErrors' Eigenschaft für weitere Details

  3. http://blogs.infosupport.com/improving-dbentityvalidationexception/

0
Atta H.