it-swarm.com.de

Die Validierung ist für eine oder mehrere Entitäten fehlgeschlagen, während Änderungen an der SQL Server-Datenbank mit Entity Framework gespeichert wurden

Ich möchte meine Bearbeitung in der Datenbank speichern und verwende Entity FrameWork Code-First in ASP.NET MVC 3/C #, aber es werden Fehler angezeigt. In meiner Event-Klasse habe ich DateTime- und TimeSpan-Datentypen, aber in meiner Datenbank habe ich Datum und Uhrzeit. Könnte das der Grund sein? Wie kann ich den entsprechenden Datentyp im Code umwandeln, bevor ich Änderungen an der Datenbank speichere?.

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 im Controller >>>> 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 '/' Anwendung.

Validierung für eine oder mehrere Entitäten fehlgeschlagen. Weitere Informationen finden Sie unter "EntityValidationErrors" -Eigenschaft.

Beschreibung: Während der Ausführung der aktuellen Webanforderung ist eine nicht behandelte Ausnahme aufgetreten. Überprüfen Sie die Stapelablaufverfolgung, um weitere Informationen zu dem Fehler und dessen Ursprung im Code zu erhalten.

Ausnahmedetails: System.Data.Entity.Validation.DbEntityValidationException: Überprüfung für eine oder mehrere Entitäten fehlgeschlagen. Weitere Informationen finden Sie unter "EntityValidationErrors" -Eigenschaft.

Quellfehler:

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: Überprüfung für eine oder mehrere Entitäten fehlgeschlagen. Weitere Informationen finden Sie unter "EntityValidationErrors" -Eigenschaft.]

331
user522767

Sie können alle Informationen aus der DbEntityValidationException mit dem folgenden Code extrahieren (Sie müssen die Namespaces System.Data.Entity.Validation und System.Diagnostics zu Ihrer using-Liste hinzufügen):

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);
        }
    }
}
838
Praveen Prasad

Keine Codeänderung erforderlich:

Ö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

oder:

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

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

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

248
GONeale

Für den Fall, dass Sie Klassen mit denselben Eigenschaftsnamen haben, ist hier eine kleine Erweiterung der Antwort von 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);
       }
    }
 }
37
Tony

Als Verbesserung für 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...
        }
    }
}
22
Bolt Thunder

Diese Implementierung schließt Entitätsausnahmen an Ausnahmen mit Detailtexten an. Es behandelt DbEntityValidationException, DbUpdateException, datetime2 Bereichsfehler (MS SQL) und schließt den Schlüssel einer ungültigen Entität in die Nachricht ein (nützlich, wenn viele Entitäten bei einem SaveChanges Aufruf gespeichert werden).

Überschreiben Sie zunächst 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);
    }
}
6
Sel

Dieser Code hat mir geholfen, mein Problem zu finden, als ich ein Problem mit meinem Entity VAlidation-Fehler hatte. Es hat mir das genaue Problem mit meiner Objektdefinition mitgeteilt. Versuchen Sie, den folgenden Code zu verwenden, um storeDB.SaveChanges () abzudecken. im folgenden versuchen catch block.

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

Ich habe diesen Fehler heute erhalten und konnte ihn eine Weile nicht beheben, aber ich habe festgestellt, dass ich meinen Modellen einige RequireAttribute hinzugefügt habe und dass einige Startdaten für die Entwicklung nicht alle erforderlichen Felder ausgefüllt haben.
Beachten Sie also, dass Sie sicherstellen müssen, dass Ihre Startdaten erfüllt und erfüllt sind, wenn Sie diesen Fehler erhalten, während Sie die Datenbank durch eine Art Init-Strategie wie DropCreateDatabaseIfModelChanges aktualisieren Validierungsattribute für Modelldaten.

Ich weiß, dass dies ein wenig anders ist als das Problem in der Frage, aber es ist eine beliebte Frage, daher dachte ich, ich würde der Antwort für andere, die das gleiche Problem haben wie ich, etwas mehr hinzufügen.
Hoffe das hilft anderen :)

4
dan richardson

Ich denke, das Hinzufügen von try/catch für jede SaveChanges() -Operation ist keine gute Übung. Es ist besser, dies zu zentralisieren:

Fügen Sie diese Klasse zur Hauptklasse DbContext hinzu:

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

Dies überschreibt die SaveChanges() -Methode Ihres Kontexts und Sie erhalten eine durch Kommas getrennte Liste mit allen Entitätsprüfungsfehlern.

dies kann auch verbessert werden, um Fehler in der Produktionsumgebung zu protokollieren, anstatt nur einen Fehler auszulösen.

hoffe das ist hilfreich.

4
Chtiwi Malek

Hier ist eine Erweiterung von Tonys Erweiterung ... :-)

Wenn Sie für Entity Framework 4.x den Namen und den Wert des Schlüsselfelds abrufen möchten, damit Sie wissen, bei welcher Entitätsinstanz (DB-Datensatz) das Problem auftritt, können Sie Folgendes hinzufügen. Dadurch erhalten Sie über Ihr DbContext-Objekt Zugriff auf die leistungsstärkeren ObjectContext-Klassenmitglieder.

// 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
Martin_ATS

Ich mag keine Ausnahmen, wenn ich die OnSaveChanges registriert habe und diese habe

var validationErrors = model.GetValidationErrors();

var h = validationErrors.SelectMany(x => x.ValidationErrors
                                          .Select(f => "Entity: " 
                                                      +(x.Entry.Entity) 
                                                      + " : " + f.PropertyName 
                                                      + "->" + f.ErrorMessage));
3

Stellen Sie sicher, dass Sie nicht versuchen, mehr als 50 Zeichen einzufügen, wenn Sie nvarchar (50) in der DB-Zeile haben. Dummer Fehler, aber ich habe 3 Stunden gebraucht, um es herauszufinden.

2
user4030144

Dieser Fehler tritt auch auf, wenn Sie versuchen, eine Entität mit Überprüfungsfehlern zu speichern. Eine gute Möglichkeit, dies zu veranlassen, besteht darin, zu vergessen, ModelState.IsValid vor dem Speichern in Ihrer Datenbank zu überprüfen.

2
laylarenee

Ich hatte vor ein paar Tagen das gleiche Problem beim Aktualisieren der Datenbank. In meinem Fall wurden zu Wartungszwecken nur wenige neue, nicht nullfähige Spalten hinzugefügt, die nicht im Code enthalten waren, der die Ausnahme verursacht. Ich finde diese Felder heraus und liefere Werte für sie und es ist gelöst.

1
JM Kumawat

Dies kann an der maximalen Anzahl von Zeichen liegen, die für eine bestimmte Spalte zulässig sind, z. B. in SQL. Ein Feld hat möglicherweise den folgenden Datentyp nvarchar(5), aber die vom Benutzer eingegebene Anzahl von Zeichen ist höher als der angegebene Wert. Daher tritt der Fehler auf .

1
lokopi

dies kann durch eine Eigenschaft verursacht werden, die nicht vom Modell ausgefüllt wird. Stattdessen wird sie vom Controller ausgefüllt. Dies kann zu diesem Fehler führen. Weisen Sie die Eigenschaft zu, bevor Sie die ModelState-Validierung anwenden. und diese zweite Annahme ist. Möglicherweise haben Sie bereits Daten in Ihrer Datenbank und versuchen, diese zu aktualisieren, holen sie jedoch jetzt.

0

Vielen Dank für Ihre Antworten, es hilft mir sehr. Wie ich in Vb.Net codiere, ist dieser Schraubencode für 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
Exatex

In meinem Fall habe ich einen Tabellenspaltennamen Pfad, dessen Datentyp ich als varchar (200) festgelegt habe. Nachdem ich ihn auf nvarchar (max) aktualisiert habe, habe ich die Tabelle aus edmx gelöscht und dann die Tabelle erneut hinzugefügt und sie ordnungsgemäß für mich erstellt.

0
Saket Singh