340 Stimmen

Validierung für eine oder mehrere Entitäten beim Speichern von Änderungen in der SQL Server-Datenbank mit Entity Framework fehlgeschlagen

Ich möchte meine bearbeiten, um Datenbank zu speichern und ich bin mit Entity FrameWork Code-First in ASP.NET MVC 3 / C#, aber ich bin immer Fehler. In meiner Ereignisklasse habe ich die Datentypen DateTime und TimeSpan, aber in meiner Datenbank habe ich Datum bzw. Uhrzeit. Könnte dies der Grund sein? Wie kann ich vor dem Speichern von Änderungen in der Datenbank den entsprechenden Datentyp im Code verwenden?

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

Methode in der Steuerung >>>> Problem bei storeDB.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);
    }
}

mit

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 Datenbank / T-SQL

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

Http-Formular

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  

Serverfehler in der Anwendung '/'.

Validierung für eine oder mehrere Entitäten fehlgeschlagen. Siehe Eigenschaft 'EntityValidationErrors' für weitere Details.

Beschreibung: Während der Ausführung der aktuellen Webanfrage ist eine unbehandelte Ausnahme aufgetreten. Bitte überprüfen Sie den Stack-Trace für weitere Informationen über den Fehler und wo er im Code entstanden ist.

Details zur Ausnahme: System.Data.Entity.Validation.DbEntityValidationException: Validierung für eine oder mehrere Entitäten fehlgeschlagen. Siehe Eigenschaft 'EntityValidationErrors' für weitere Details.

Fehlerquelle:

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

Quelldatei: C:\sep\MvcEventCalendar\MvcEventCalendar\Controllers\EventManagerController.cs Zeile: 77

Stack Trace:

[DbEntityValidationException: Validierung für eine oder mehrere Entitäten fehlgeschlagen. Siehe Eigenschaft 'EntityValidationErrors' für weitere Details].

838voto

Praveen Prasad Punkte 30631

Sie können alle Informationen aus der DbEntityValidationException mit folgendem Code (Sie müssen die Namespaces hinzufügen: System.Data.Entity.Validation y System.Diagnostics zu Ihrem 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);
        }
    }
}

249voto

GONeale Punkte 25883

Keine Codeänderung erforderlich:

Während Sie sich im Debug-Modus innerhalb der catch {...} Block öffnen Sie das Fenster "QuickWatch" ( Ctrl + Alt + Q ) und fügen Sie dort ein:

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

oder:

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

Wenn Sie sich nicht in einem try/catch befinden oder keinen Zugriff auf das Ausnahmeobjekt haben.

So können Sie die folgenden Informationen aufschlüsseln ValidationErrors Baum. Das ist der einfachste Weg, den ich gefunden habe, um einen sofortigen Einblick in diese Fehler zu bekommen.

37voto

Tony Punkte 1516

Für den Fall, dass Sie Klassen mit gleichen Eigenschaftsnamen haben, hier eine kleine Erweiterung zu Praveens Antwort:

 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);
       }
    }
 }

22voto

Bolt Thunder Punkte 735

Als Verbesserung zu Praveen und Tony verwende ich einen Override:

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...
        }
    }
}

6voto

Sel Punkte 1834

Diese Implementierung wrap Entität Ausnahme zu Ausnahme mit Detailtext. Sie behandelt DbEntityValidationException , DbUpdateException , datetime2 Bereichsfehler (MS SQL), und fügen Sie den Schlüssel der ungültigen Entität in die Nachricht ein (nützlich, wenn viele Entitäten auf einmal gespeichert werden SaveChanges Aufruf).

Erstens: Überschreiben Sie SaveChanges in der DbContext-Klasse:

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-Klasse:

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);
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X