Convalida non riuscita per una o più quadro. Vedi la proprietà ‘EntityValidationErrors’ per maggiori dettagli

Sto riscontrando questo errore quando ho seminato il mio database con il primo approccio al codice.

Convalida non riuscita per una o più entity framework. Vedi la proprietà ‘EntityValidationErrors’ per maggiori dettagli.

Per essere onesti, non so come controllare il contenuto degli errori di convalida. Visual Studio mi mostra che si tratta di un array con 8 oggetti, quindi 8 errori di convalida.

Questo funzionava con il mio modello precedente, ma ho apportato alcune modifiche che spiego di seguito:

  • Avevo un enum chiamato Status, l’ho cambiato in una class chiamata Status
  • Ho cambiato la class ApplicantsPositionHistory per avere 2 chiavi esterne per la stessa tabella

Scusami per il lungo codice, ma devo incollarlo tutto. L’eccezione è generata nell’ultima riga del seguente codice.

namespace Data.Model { public class Position { [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)] public int PositionID { get; set; } [Required(ErrorMessage = "Position name is required.")] [StringLength(20, MinimumLength = 3, ErrorMessage = "Name should not be longer than 20 characters.")] [Display(Name = "Position name")] public string name { get; set; } [Required(ErrorMessage = "Number of years is required")] [Display(Name = "Number of years")] public int yearsExperienceRequired { get; set; } public virtual ICollection applicantPosition { get; set; } } public class Applicant { [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)] public int ApplicantID { get; set; } [Required(ErrorMessage = "Name is required")] [StringLength(20, MinimumLength = 3, ErrorMessage="Name should not be longer than 20 characters.")] [Display(Name = "First and LastName")] public string name { get; set; } [Required(ErrorMessage = "Telephone number is required")] [StringLength(10, MinimumLength = 3, ErrorMessage = "Telephone should not be longer than 20 characters.")] [Display(Name = "Telephone Number")] public string telephone { get; set; } [Required(ErrorMessage = "Skype username is required")] [StringLength(10, MinimumLength = 3, ErrorMessage = "Skype user should not be longer than 20 characters.")] [Display(Name = "Skype Username")] public string skypeuser { get; set; } public byte[] photo { get; set; } public virtual ICollection applicantPosition { get; set; } } public class ApplicantPosition { [Key] [Column("ApplicantID", Order = 0)] public int ApplicantID { get; set; } [Key] [Column("PositionID", Order = 1)] public int PositionID { get; set; } public virtual Position Position { get; set; } public virtual Applicant Applicant { get; set; } [Required(ErrorMessage = "Applied date is required")] [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)] [Display(Name = "Date applied")] public DateTime appliedDate { get; set; } [Column("StatusID", Order = 0)] public int StatusID { get; set; } public Status CurrentStatus { get; set; } //[NotMapped] //public int numberOfApplicantsApplied //{ // get // { // int query = // (from ap in Position // where ap.Status == (int)Status.Applied // select ap // ).Count(); // return query; // } //} } public class Address { [StringLength(20, MinimumLength = 3, ErrorMessage = "Country should not be longer than 20 characters.")] public string Country { get; set; } [StringLength(20, MinimumLength = 3, ErrorMessage = "City should not be longer than 20 characters.")] public string City { get; set; } [StringLength(50, MinimumLength = 3, ErrorMessage = "Address should not be longer than 50 characters.")] [Display(Name = "Address Line 1")] public string AddressLine1 { get; set; } [Display(Name = "Address Line 2")] public string AddressLine2 { get; set; } } public class ApplicationPositionHistory { [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)] public int ApplicationPositionHistoryID { get; set; } public ApplicantPosition applicantPosition { get; set; } [Column("oldStatusID")] public int oldStatusID { get; set; } [Column("newStatusID")] public int newStatusID { get; set; } public Status oldStatus { get; set; } public Status newStatus { get; set; } [StringLength(500, MinimumLength = 3, ErrorMessage = "Comments should not be longer than 500 characters.")] [Display(Name = "Comments")] public string comments { get; set; } [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)] [Display(Name = "Date")] public DateTime dateModified { get; set; } } public class Status { [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)] public int StatusID { get; set; } [StringLength(20, MinimumLength = 3, ErrorMessage = "Status should not be longer than 20 characters.")] [Display(Name = "Status")] public string status { get; set; } } } 

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Entity; using System.IO; namespace Data.Model { public class HRContextInitializer : DropCreateDatabaseAlways { protected override void Seed(HRContext context) { #region Status Status applied = new Status() { status = "Applied" }; Status reviewedByHR = new Status() { status = "Reviewed By HR" }; Status approvedByHR = new Status() { status = "Approved by HR" }; Status rejectedByHR = new Status() { status = "Rejected by HR" }; Status assignedToTechnicalDepartment = new Status() { status = "Assigned to Technical Department" }; Status approvedByTechnicalDepartment = new Status() { status = "Approved by Technical Department" }; Status rejectedByTechnicalDepartment = new Status() { status = "Rejected by Technical Department" }; Status assignedToGeneralManager = new Status() { status = "Assigned to General Manager" }; Status approvedByGeneralManager = new Status() { status = "Approved by General Manager" }; Status rejectedByGeneralManager = new Status() { status = "Rejected by General Manager" }; context.Status.Add(applied); context.Status.Add(reviewedByHR); context.Status.Add(approvedByHR); context.Status.Add(rejectedByHR); context.Status.Add(assignedToTechnicalDepartment); context.Status.Add(approvedByTechnicalDepartment); context.Status.Add(rejectedByTechnicalDepartment); context.Status.Add(assignedToGeneralManager); context.Status.Add(approvedByGeneralManager); context.Status.Add(rejectedByGeneralManager); #endregion #region Position Position netdeveloper = new Position() { name = ".net developer", yearsExperienceRequired = 5 }; Position javadeveloper = new Position() { name = "java developer", yearsExperienceRequired = 5 }; context.Positions.Add(netdeveloper); context.Positions.Add(javadeveloper); #endregion #region Applicants Applicant luis = new Applicant() { name = "Luis", skypeuser = "le.valencia", telephone = "0491732825", photo = File.ReadAllBytes(@"C:\Users\LUIS.SIMBIOS\Documents\Visual Studio 2010\Projects\SlnHR\HRRazorForms\Content\pictures\1.jpg") }; Applicant john = new Applicant() { name = "John", skypeuser = "jo.valencia", telephone = "3435343543", photo = File.ReadAllBytes(@"C:\Users\LUIS.SIMBIOS\Documents\Visual Studio 2010\Projects\SlnHR\HRRazorForms\Content\pictures\2.jpg") }; context.Applicants.Add(luis); context.Applicants.Add(john); #endregion #region ApplicantsPositions ApplicantPosition appicantposition = new ApplicantPosition() { Applicant = luis, Position = netdeveloper, appliedDate = DateTime.Today, StatusID = 1 }; ApplicantPosition appicantposition2 = new ApplicantPosition() { Applicant = john, Position = javadeveloper, appliedDate = DateTime.Today, StatusID = 1 }; context.ApplicantsPositions.Add(appicantposition); context.ApplicantsPositions.Add(appicantposition2); #endregion context.SaveChanges(); --->> Error here } } } 

Per essere onesti, non so come controllare il contenuto degli errori di convalida. Visual Studio mi mostra che si tratta di un array con 8 oggetti, quindi 8 errori di convalida.

In realtà dovresti vedere gli errori se esegui il drill su quell’array in Visual Studio durante il debug. Ma puoi anche catturare l’eccezione e quindi scrivere gli errori in qualche archivio di registrazione o nella console:

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

EntityValidationErrors è una raccolta che rappresenta le quadro che non possono essere convalidate correttamente e la raccolta interna ValidationErrors per quadro è una lista di errori a livello di proprietà.

Questi messaggi di convalida sono di solito abbastanza utili per trovare la fonte del problema.

modificare

Alcuni piccoli miglioramenti:

Il valore della proprietà incriminata può essere incluso nel ciclo interno in questo modo:

  foreach (var ve in eve.ValidationErrors) { Console.WriteLine("- Property: \"{0}\", Value: \"{1}\", Error: \"{2}\"", ve.PropertyName, eve.Entry.CurrentValues.GetValue(ve.PropertyName), ve.ErrorMessage); } 

Mentre il debug di Debug.Write potrebbe essere preferibile su Console.WriteLine poiché funziona in tutti i tipi di applicazioni, non solo nelle applicazioni della console (grazie a @Bart per la sua nota nei commenti sotto).

Per le applicazioni Web in produzione e che utilizzano Elmah per la registrazione delle eccezioni, è stato molto utile per me creare un’eccezione personalizzata e sovrascrivere SaveChanges per lanciare questa nuova eccezione.

Il tipo di eccezione personalizzata si presenta così:

 public class FormattedDbEntityValidationException : Exception { public FormattedDbEntityValidationException(DbEntityValidationException innerException) : base(null, innerException) { } public override string Message { get { var innerException = InnerException as DbEntityValidationException; if (innerException != null) { StringBuilder sb = new StringBuilder(); sb.AppendLine(); sb.AppendLine(); foreach (var eve in innerException.EntityValidationErrors) { sb.AppendLine(string.Format("- Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", eve.Entry.Entity.GetType().FullName, eve.Entry.State)); foreach (var ve in eve.ValidationErrors) { sb.AppendLine(string.Format("-- Property: \"{0}\", Value: \"{1}\", Error: \"{2}\"", ve.PropertyName, eve.Entry.CurrentValues.GetValue(ve.PropertyName), ve.ErrorMessage)); } } sb.AppendLine(); return sb.ToString(); } return base.Message; } } } 

E SaveChanges può essere sovrascritto nel seguente modo:

 public class MyContext : DbContext { // ... public override int SaveChanges() { try { return base.SaveChanges(); } catch (DbEntityValidationException e) { var newException = new FormattedDbEntityValidationException(e); throw newException; } } } 

Alcune osservazioni:

  • La schermata gialla di errore mostrata da Elmah nell’interfaccia Web o nelle e-mail inviate (se questa è stata configurata) visualizza ora i dettagli di convalida direttamente nella parte superiore del messaggio.

  • Sovrascrivere la proprietà Message nell’eccezione personalizzata invece di sovrascrivere ToString() ha il vantaggio che lo standard ASP.NET “Yellow screen of death (YSOD)” visualizza anche questo messaggio. A differenza di Elmah, YSOD apparentemente non usa ToString() , ma entrambi visualizzano la proprietà Message .

  • Il DbEntityValidationException di DbEntityValidationException originale come eccezione interna garantisce che la traccia dello stack originale sia ancora disponibile e visualizzata in Elmah e YSOD.

  • Impostando un punto di interruzione sulla linea si throw newException; puoi semplicemente ispezionare la proprietà newException.Message come testo invece di eseguire il drilling nelle raccolte di convalida, che è un po ‘scomodo e non sembra funzionare facilmente per tutti (vedi i commenti sotto).

Puoi farlo da Visual Studio durante il debug senza scrivere alcun codice, nemmeno un blocco catch.

Basta aggiungere un orologio con il nome:

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

L’ $exception watch watch visualizza qualsiasi eccezione generata nel contesto corrente, anche se non è stata catturata e assegnata a una variabile.

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

Questo potrebbe davvero farlo senza dover scrivere codice:

Nel blocco catch, aggiungi un punto di interruzione alla seguente riga di codice:

 catch (Exception exception) { } 

Ora, se si passa con il mouse su exception o lo si aggiunge Watch quindi navigare nei dettagli dell’eccezione come mostrato di seguito; vedrai quale / e particolare / e colonna / e sta causando il problema poiché questo errore di solito si verifica quando un vincolo di tabella viene violato.

inserisci la descrizione dell'immagine qui

Immagine grande

Ecco come è ansible controllare il contenuto di EntityValidationErrors in Visual Studio (senza scrivere alcun codice aggiuntivo), ad esempio durante il debug nell’IDE .

Il problema?

Hai ragione, la finestra View Details Popup del debugger di Visual Studio non mostra gli errori effettivi all’interno della collezione EntityValidationErrors .

inserisci la descrizione dell'immagine qui

La soluzione!

Basta aggiungere la seguente espressione in una finestra di Quick Watch e fare clic su Rivaluta .

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

Nel mio caso, vedere come sono in grado di espandermi nell’elenco ValidationErrors all’interno della collezione EntityValidationErrors

inserisci la descrizione dell'immagine qui

Riferimenti: post del blog mattrandle.me , risposta di @ yoel

Per un modo rapido di vedere il primo errore senza nemmeno aggiungere un orologio, è ansible incollarlo nella finestra immediata:

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

Per chiunque lavori in VB.NET

 Try Catch ex As DbEntityValidationException For Each a In ex.EntityValidationErrors For Each b In a.ValidationErrors Dim st1 As String = b.PropertyName Dim st2 As String = b.ErrorMessage Next Next End Try 

Mentre sei in modalità di debug all’interno del catch {...} , apri la finestra “QuickWatch” ( ctrl + alt + q ) e incollaci lì:

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

o:

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

Se non si è in un try / catch o non si ha accesso all’object exception.

Ciò ti consentirà di eseguire il drill-down nell’albero ValidationErrors . È il modo più semplice che ho trovato per ottenere una visione immediata di questi errori.

Se stai semplicemente rilevando un’eccezione generica, potrebbe essere utile eseguire il cast come DbEntityValidationException . Questo tipo di eccezione ha una proprietà Errori di convalida e, continuando ad espandervi, troverete tutti i problemi.

Ad esempio, se inserisci un punto di interruzione nella cattura, puoi lanciare quanto segue in un orologio:

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

Un esempio di errore è che se un campo non consente valori nulli e si dispone di una stringa nulla, lo si vedrà affermare che il campo è obbligatorio.

Nel debug, è ansible inserire questo nel campo della voce di valutazione dell’espressione QuickWatch:

 context.GetValidationErrors() 

basta controllare la lunghezza del campo della tabella del database. Il testo di input è maggiore della lunghezza della lunghezza del tipo di dati del campo colonna

Ho dovuto scrivere questo nella finestra immediata: 3

 (((exception as System.Data.Entity.Validation.DbEntityValidationException).EntityValidationErrors as System.Collections.Generic.List)[0].ValidationErrors as System.Collections.Generic.List)[0] 

al fine di ottenere in profondità l’errore esatto!

Si noti che Entity.GetType().BaseType.Name fornisce il nome del tipo specificato, non quello con tutte le cifre esadecimali nel suo nome.

Usando la risposta di @Slauma ho creato uno snippet di codice (un surround con snippet) per un uso migliore.

    
SurroundsWith ValidationErrorsTryCatch Phoenix

Per @ risposta di Slauma e suggerimento di @ Milton ho esteso il metodo di salvataggio personalizzato della nostra class base con un try / catch che gestirà (e quindi accederà alla nostra registrazione degli errori!) Questo tipo di eccezioni.

 // Where `BaseDB` is your Entities object... (it could be `this` in a different design) public void Save(bool? validateEntities = null) { try { //Capture and set the validation state if we decide to bool validateOnSaveEnabledStartState = BaseDB.Configuration.ValidateOnSaveEnabled; if (validateEntities.HasValue) BaseDB.Configuration.ValidateOnSaveEnabled = validateEntities.Value; BaseDB.SaveChanges(); //Revert the validation state when done if (validateEntities.HasValue) BaseDB.Configuration.ValidateOnSaveEnabled = validateOnSaveEnabledStartState; } catch (DbEntityValidationException e) { StringBuilder sb = new StringBuilder(); foreach (var eve in e.EntityValidationErrors) { sb.AppendLine(string.Format("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) { sb.AppendLine(string.Format("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage)); } } throw new DbEntityValidationException(sb.ToString(), e); } } 

Cattura l’eccezione in un catch di prova e poi guarda rapidamente o ctrl + d & ctrl + q e puoi eseguire il drill-down su EntityValidationErrors.

La risposta di @Slauma è davvero eccezionale, ma ho scoperto che non funzionava quando una proprietà ComplexType non era valida.

Ad esempio, supponiamo di avere un Phone di proprietà del tipo complesso PhoneNumber . Se la proprietà AreaCode non è valida, il nome della proprietà in ve.PropertyNames è “Phone.AreaCode”. Ciò causa il eve.Entry.CurrentValues(ve.PropertyName) della chiamata a eve.Entry.CurrentValues(ve.PropertyName) .

Per risolvere questo problema, puoi dividere il nome della proprietà su ciascuno . , quindi ricorrere alla matrice risultante di nomi di proprietà. Infine, quando arrivi in ​​fondo alla catena, puoi semplicemente restituire il valore della proprietà.

Di seguito è riportata la class FormattedDbEntityValidationException @ Slauma con supporto per ComplexTypes.

Godere!

 [Serializable] public class FormattedDbEntityValidationException : Exception { public FormattedDbEntityValidationException(DbEntityValidationException innerException) : base(null, innerException) { } public override string Message { get { var innerException = InnerException as DbEntityValidationException; if (innerException == null) return base.Message; var sb = new StringBuilder(); sb.AppendLine(); sb.AppendLine(); foreach (var eve in innerException.EntityValidationErrors) { sb.AppendLine(string.Format("- Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", eve.Entry.Entity.GetType().FullName, eve.Entry.State)); foreach (var ve in eve.ValidationErrors) { object value; if (ve.PropertyName.Contains(".")) { var propertyChain = ve.PropertyName.Split('.'); var complexProperty = eve.Entry.CurrentValues.GetValue(propertyChain.First()); value = GetComplexPropertyValue(complexProperty, propertyChain.Skip(1).ToArray()); } else { value = eve.Entry.CurrentValues.GetValue(ve.PropertyName); } sb.AppendLine(string.Format("-- Property: \"{0}\", Value: \"{1}\", Error: \"{2}\"", ve.PropertyName, value, ve.ErrorMessage)); } } sb.AppendLine(); return sb.ToString(); } } private static object GetComplexPropertyValue(DbPropertyValues propertyValues, string[] propertyChain) { var propertyName = propertyChain.First(); return propertyChain.Count() == 1 ? propertyValues[propertyName] : GetComplexPropertyValue((DbPropertyValues)propertyValues[propertyName], propertyChain.Skip(1).ToArray()); } } 

Sto solo buttando i miei due centesimi in …

All’interno del mio dbConfiguration.cs, mi piace avvolgere il mio metodo context.SaveChanges () in un try / catch e produrre un file di testo di output che mi permetta di leggere chiaramente gli errori, e questo codice li timestamp – pratici se incorrere in più di un errore in tempi diversi!

  try { context.SaveChanges(); } catch (DbEntityValidationException e) { //Create empty list to capture Validation error(s) var outputLines = new List(); foreach (var eve in e.EntityValidationErrors) { outputLines.Add( $"{DateTime.Now}: Entity of type \"{eve.Entry.Entity.GetType().Name}\" in state \"{eve.Entry.State}\" has the following validation errors:"); outputLines.AddRange(eve.ValidationErrors.Select(ve => $"- Property: \"{ve.PropertyName}\", Error: \"{ve.ErrorMessage}\"")); } //Write to external file File.AppendAllLines(@"c:\temp\dbErrors.txt", outputLines); throw; } 

Quello che ho trovato … quando ho l’errore ‘EntityValidationErrors’ è che …. ho un campo nel mio database ‘db1’ nella tabella ‘tbladdress’ come ‘address1’ che ha dimensione di 100 (cioè indirizzo varchar (100) null) e stavo passando il valore più di 100 caratteri … e questo ha comportato errori durante il salvataggio dei dati nel database ….

Quindi devi controllare i dati che stai passando al campo.

Questo funziona per me.

 var modelState = ModelState.Values; if (!ModelState.IsValid) { return RedirectToAction("Index", "Home", model); } 

Metti un punto di interruzione su se dichiarazione. Quindi puoi controllare modelState in debug windows. Su ogni valore puoi vedere se c’è un errore e persino il messaggio di errore. Questo è tutto. Quando non ne hai più bisogno, elimina o commenta la linea.

Spero che questo ti possa aiutare.

Se richiesto, posso fornire screenshot dettagliato nella finestra di debug.

Come menzionato in altri post, è sufficiente rilevare l’eccezione nella class DbEntityValidationException. Quale ti darà il watever richiesto durante i casi di errore.

  try { .... } catch(DbEntityValidationException ex) { .... } 

Ho affrontato questo errore prima

quando ho provato ad aggiornare il campo specifico nel mio modello in framwork di entity framework

 Letter letter = new Letter {ID = letterId, ExportNumber = letterExportNumber,EntityState = EntityState.Modified}; LetterService.ChangeExportNumberfor(letter); //---------- public int ChangeExportNumber(Letter letter) { int result = 0; using (var db = ((LettersGeneratorEntities) GetContext())) { db.Letters.Attach(letter); db.Entry(letter).Property(x => x.ExportNumber).IsModified = true; result += db.SaveChanges(); } return result; } 

e secondo le risposte di cui sopra

Ho trovato il messaggio di convalida The SignerName field is required.

che punta al campo nel mio modello

e quando ho controllato il mio schema di database ho trovato

inserisci la descrizione dell'immagine qui

quindi off coure ValidationException ha il diritto di aumentare

e secondo questo campo voglio che sia annullabile, (non so come l’ho incasinato)

quindi ho cambiato campo per consentire a Null, e con questo il mio codice non mi darà ancora questo errore

quindi questo errore potrebbe accadere se si invalida l’integrità dei dati del proprio database

Controlla i valori dei campi che stai passando, sono validi e in base ai campi del database. Ad esempio, il numero di caratteri passati in un campo particolare è inferiore ai caratteri definiti nel campo della tabella del database.

Se stai utilizzando IIS con Authentification di Windows ed Entity Framework , fai attenzione a usare authorize .

Ho provato a POST senza autorizzare e non ha funzionato, e ottenere questo errore su db.SaveChangesAsync(); , mentre tutti gli altri verbi GET e DELETE stavano funzionando.

Ma quando ho aggiunto AuthorizeAttribute come annotazione, ha funzionato.

 [Authorize] public async Task Post(...){ .... } 

Controlla se non hai un vincolo Not Null nelle colonne della tabella e non passi il valore per quella colonna durante le operazioni di inserimento / aggiornamento. Che causa questa eccezione nel framework di entity framework.