Sprawdzanie poprawności nie powiodło się dla jednego lub więcej podmiotów. Aby uzyskać więcej informacji, zobacz właściwość „EntityValidationErrors”


804

Wystąpił ten błąd podczas inicjowania mojej bazy danych przy pierwszym podejściu do kodu.

Sprawdzanie poprawności nie powiodło się dla jednego lub więcej podmiotów. Aby uzyskać więcej informacji, zobacz właściwość „EntityValidationErrors”.

Szczerze mówiąc, nie wiem, jak sprawdzić zawartość błędów sprawdzania poprawności. Visual Studio pokazuje mi, że jest to tablica z 8 obiektami, więc 8 błędów sprawdzania poprawności.

Działało to z moim poprzednim modelem, ale wprowadziłem kilka zmian, które wyjaśniam poniżej:

  • Miałem wyliczenie o nazwie Status, zmieniłem je na klasę o nazwie Status
  • Zmieniłem klasę ApplicantsPositionHistory, aby mieć 2 klucze obce do tej samej tabeli

Przepraszam za długi kod, ale muszę go wkleić. Wyjątek jest zgłaszany w ostatnim wierszu następującego kodu.

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> 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> 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<HRContext>
    {
        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
        }
    }
}

Odpowiedzi:


1237

Szczerze mówiąc, nie wiem, jak sprawdzić zawartość błędów sprawdzania poprawności. Visual Studio pokazuje mi, że jest to tablica z 8 obiektami, więc 8 błędów sprawdzania poprawności.

Właściwie powinieneś zobaczyć błędy, jeśli wykonasz drążenie tej tablicy w Visual Studio podczas debugowania. Ale możesz również złapać wyjątek, a następnie zapisać błędy w sklepie z logami lub na konsoli:

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

EntityValidationErrorsjest kolekcją reprezentującą jednostki, których nie można pomyślnie zweryfikować, a wewnętrzna kolekcja ValidationErrorsna jednostkę to lista błędów na poziomie właściwości.

Te komunikaty sprawdzania poprawności są zwykle wystarczająco pomocne, aby znaleźć źródło problemu.

Edytować

Kilka drobnych ulepszeń:

Wartość właściwości naruszającego przepisy mogą być zawarte w wewnętrznej pętli tak:

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

Podczas gdy debugowanie Debug.Writemoże być preferowane, Console.WriteLineponieważ działa we wszelkiego rodzaju aplikacjach, nie tylko w aplikacjach konsolowych (dzięki @Bart za notatkę w komentarzach poniżej).

W przypadku aplikacji internetowych, które są w produkcji i używają Elmah do rejestrowania wyjątków, bardzo przydało mi się utworzenie niestandardowego wyjątku i zastąpienie go SaveChangesw celu wyrzucenia tego nowego wyjątku.

Niestandardowy typ wyjątku wygląda następująco:

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<object>(ve.PropertyName),
                            ve.ErrorMessage));
                    }
                }
                sb.AppendLine();

                return sb.ToString();
            }

            return base.Message;
        }
    }
}

I SaveChangesmoże być zastąpiony w następujący sposób:

public class MyContext : DbContext
{
    // ...

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

Kilka uwag:

  • Żółty ekran błędu, który Elmah pokazuje w interfejsie internetowym lub w wysłanych wiadomościach e-mail (jeśli skonfigurowałeś to), teraz wyświetla szczegóły sprawdzania poprawności bezpośrednio u góry wiadomości.

  • Zastąpienie Messagewłaściwości w niestandardowym wyjątku zamiast zastąpienia ToString()ma tę zaletę, że standardowy komunikat ASP.NET „Żółty ekran śmierci (YSOD)” wyświetla również ten komunikat. W przeciwieństwie do Elmah, YSOD najwyraźniej nie używa ToString(), ale oba wyświetlają Messagewłaściwość.

  • Zawijanie oryginału DbEntityValidationExceptionjako wewnętrznego wyjątku zapewnia, że ​​ślad stosu oryginalnego będzie nadal dostępny i będzie wyświetlany w Elmah i YSOD.

  • Ustawiając punkt przerwania w wierszu throw newException;, możesz po prostu sprawdzić newException.Messagewłaściwość jako tekst zamiast wiercić w kolekcjach sprawdzania poprawności, co jest nieco niewygodne i wydaje się, że nie działa łatwo dla wszystkich (patrz komentarze poniżej).


87
Wiercenie w wyjątku nic nie robi. Mówi tylko, że istnieje DbEntityValidationResult, ale nie pozwala Ci się rozwijać!
Shumii

30
@Shumii Zobacz tę odpowiedź, aby rozwinąć wyjątek.
Cavyn VonDeylen

18
Aby rozszerzyć eleganckie rozwiązanie. Możesz zastąpić metodę savechanges we własnej klasie DbContext, a następnie dodać blok try catch, w którym blok try tylko próbuje zapisać (base.SaveChanges ()), a blok catch przechwytuje tylko wyjątek DbEntityValidationException. W ten sposób nie musisz dodawać go w każdym miejscu, w którym zapisujesz zmiany.
Milton,

7
To uratowało mój bekon przy więcej niż jednej okazji. Mogłem głosować tylko raz. Szkoda, że ​​nie pozwolą mi głosować za każdym razem, gdy to kopiuję i wklejam.
Damon Drake,

5
+2 za kod. Rzeczywiście zbawicielem :) -1 za korzystanie Console.WriteLine, szacuję więcej ludzi pisania projektów internetowych następnie pocieszyć aplikacje w dzisiejszych czasach, a Debug.Writedziała w obie ...
Bart

459

Możesz to zrobić w programie Visual Studio podczas debugowania bez pisania kodu, nawet bloku catch.

Wystarczy dodać zegarek o nazwie:

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

Wyrażenie obserwacyjne $exceptionwyświetla każdy wyjątek zgłoszony w bieżącym kontekście, nawet jeśli nie został złapany i przypisany do zmiennej.

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


39
+1 O wiele lepsze rozwiązanie i nie wymaga zmian w kodzie. Cool
Justas

4
+1 to jest bardzo, bardzo przydatne! Nie musisz nawet mieć bloku try / catch. Po prostu zaznacz to na liście obserwacyjnej, gdy VS się zepsuje i voila ... masz przed sobą błędy sprawdzania poprawności.
theyetiman

40
kilka razy w roku zapominam, jak to zrobić i znajduję tę odpowiedź
Justin Moore,

3
@zairja Nie testowałem tego w vb.net, ale wygląda na to, że zmienna jest również zdefiniowana dla vb.net w msdn.microsoft.com/en-us/library/ms164891.aspx , ale obsada prawdopodobnie nie jest zdefiniowane dla vb.net, a zamiast tego prawdopodobnie powinieneś wykonać DirectCast ($ wyjątek, System.Data.Entity.Validation.DbEntityValidationException)
yoel halb

2
Wiem, że „podziękowania” nie są mile widziane w komentarzach, ale w celu zapobieżenia mi godzin marnowania czasu… dzięki!
Luther

105

Może to faktycznie zrobić bez konieczności pisania kodu:

W swoim bloku catch dodaj punkt przerwania w następującym wierszu kodu:

catch (Exception exception)
{

}

Teraz, jeśli umieścisz exceptionwskaźnik myszy lub dodasz go, Watcha następnie przejdziesz do szczegółów wyjątku, jak pokazano poniżej; zobaczysz, które kolumny powodują problem, ponieważ ten błąd zwykle występuje, gdy naruszone jest ograniczenie tabeli.

wprowadź opis zdjęcia tutaj

Duży obraz


4
To podejście jest bardzo proste i wykorzystuje IDE :)
dsnunez

3
To dobre rozwiązanie, ponieważ jest szybkie, proste, korzysta z IDE i oszczędza mi mnóstwo czasu.
maxshuty,

2
Podoba mi się w ten sposób „Jak być programistą i nie robić kodu”
otwarty i darmowy

1
Dziękuję Ci. Jest to proste, ale niesamowite jest wyświetlanie wyjątku za pomocą IDE.
Thomas.Benz

idealne rozwiązanie
Neeraj Singh Chouhan

46

Oto jak możesz sprawdzić zawartość EntityValidationErrors w Visual Studio (bez pisania dodatkowego kodu), tj. Podczas debugowania w IDE .

Problem?

Masz rację, wyskakujące okienko Wyświetl szczegóły debugera programu Visual Studio nie pokazuje rzeczywistych błędów w EntityValidationErrorskolekcji.

wprowadź opis zdjęcia tutaj

Rozwiązanie!

Wystarczy dodać następujące wyrażenie w oknie Szybki podgląd i kliknąć Ponownie oszacuj .

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

W moim przypadku, zobaczyć, jak jestem w stanie ekspansji na ValidationErrors Listwewnątrz EntityValidationErrorskolekcji

wprowadź opis zdjęcia tutaj

Odnośniki: post na blogu mattrandle.me , odpowiedź @ yoel


3
dlaczego to nie zostało naprawione? powinien pokazywać błąd, a nie coś innego
Geomorillo

2
Błąd sprawdzania poprawności pokazuje błąd właściwości, np. pole tematu jest wymagane, dobra odpowiedź, dziękuję
hamzeh.hanandeh

1
Świetny! Uratowało mi to noc! :)
Patrick,

1
to inteligentny sposób na wizualizację dokładnego błędu w zegarku ... dziękuję!
Qwerty

39

Aby szybko zobaczyć pierwszy błąd bez dodawania zegarka, możesz go wkleić w oknie natychmiastowym:

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

1
Możesz także użyć $ wyjątek.EntityValidationErrors.SelectMany (x => x.ValidationErrors) .Wybierz (x => x.ErrorMessage), aby uzyskać je wszystkie :) imho za pomocą bezpośredniego okna jest najlepszą odpowiedzią
chrispepper1989

15

Dla każdego, kto pracuje 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

12

W trybie debugowania w catch {...}bloku otwórz okno „QuickWatch” ( ctrl+ alt+ q) i wklej tam:

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

lub:

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

Jeśli nie próbujesz / złapiesz lub nie masz dostępu do obiektu wyjątku.

To pozwoli ci zejść do ValidationErrorsdrzewa. To najłatwiejszy sposób, w jaki udało mi się uzyskać natychmiastowy wgląd w te błędy.


10

Jeśli po prostu wychwytujesz ogólny wyjątek, skorzystanie z niego może być przydatne jako wyjątek DbEntityValidationException . Ten typ wyjątku ma właściwość Błędy sprawdzania poprawności, a przy dalszym rozszerzaniu się na nie znajdziesz wszystkie problemy.

Na przykład, jeśli umieścisz punkt przerwania w zaczepie, możesz wrzucić do zegarka:

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

Przykładem błędu jest to, że jeśli pole nie dopuszcza wartości zerowych, a masz ciąg zerowy, zobaczysz, że pole jest wymagane.


9

wystarczy sprawdzić długość pola tabeli bazy danych. Tekst wejściowy jest większy niż długość typu danych pola kolumny


9

W debugowaniu możesz wprowadzić to w polu wprowadzania oceny wyrażeń QuickWatch:

context.GetValidationErrors()

8

Odpowiedź z @Slauma jest naprawdę świetna, ale okazało się, że nie działała, gdy właściwość ComplexType była nieprawidłowa.

Załóżmy na przykład, że masz właściwość Phonetypu złożonego PhoneNumber. Jeśli AreaCodewłaściwość jest nieprawidłowa, nazwa właściwości w ve.PropertyNamesto „Phone.AreaCode”. Powoduje eve.Entry.CurrentValues<object>(ve.PropertyName)to niepowodzenie połączenia.

Aby to naprawić, możesz podzielić nazwę właściwości dla każdej z nich ., a następnie ponownie przejrzeć wynikową tablicę nazw właściwości. Wreszcie, gdy dojdziesz do dolnej części łańcucha, możesz po prostu zwrócić wartość nieruchomości.

Poniżej znajduje się FormattedDbEntityValidationExceptionklasa @ Slauma ze wsparciem dla ComplexTypes.

Cieszyć się!

[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<DbPropertyValues>(propertyChain.First());
                        value = GetComplexPropertyValue(complexProperty, propertyChain.Skip(1).ToArray());
                    }
                    else
                    {
                        value = eve.Entry.CurrentValues.GetValue<object>(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());
    }
}

1
Nie mogę uwierzyć, że więcej ludzi nie głosowało na ten temat, ponieważ jest to bardzo prawdziwy scenariusz i doprowadza mnie to do szału przez ostatnie dwie noce. Czy wiesz, jakie uczucie odczuwasz, gdy zdajesz sobie sprawę z tego, że radzisz sobie z błędami, tak naprawdę powoduje błąd? Ugh.
DJ Grossman

7

Zauważ, że Entity.GetType().BaseType.Namepodaje nazwę typu, którą określiłeś, a nie tę ze wszystkimi cyframi szesnastkowymi w jej nazwie.


7

Na odpowiedź @ Slauma i sugestię @ Miltona rozszerzyłem niestandardową metodę składowania naszej klasy podstawowej o try / catch, który poradzi sobie (i tym samym zaloguje się przy logowaniu błędów!) Tego rodzaju wyjątki.

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

1
Możesz użyć sb.AppendFormat () bezpośrednio
Bastien Vandamme,

1
Musisz również dodać własną linię, jeśli używasz AppendFormat.
jocull

7

Musiałem napisać to w oknie natychmiastowym: 3

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

aby zagłębić się w dokładny błąd!


6

Korzystając z odpowiedzi @Slauma, stworzyłem fragment kodu (otacza go fragmentem) dla lepszego wykorzystania.

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <SnippetTypes>
        <SnippetType>SurroundsWith</SnippetType>
      </SnippetTypes>
      <Title>ValidationErrorsTryCatch</Title>
      <Author>Phoenix</Author>
      <Description>
      </Description>
      <HelpUrl>
      </HelpUrl>
      <Shortcut>
      </Shortcut>
    </Header>
    <Snippet>
      <Code Language="csharp"><![CDATA[try
{
    $selected$ $end$
}
catch (System.Data.Entity.Validation.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;
}]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

5

Złap wyjątek w try catch, a następnie szybko obejrzyj lub ctrl + d & ctrl + q i możesz przejść do szczegółów EntityValidationErrors.


5

Wrzucam tylko dwa centy ...

W moim pliku dbConfiguration.cs lubię zawijać metodę context.SaveChanges () w try / catch i produkować wyjściowy plik tekstowy, który pozwala mi na wyraźne odczytanie błędów (błędów), a ten kod także znaczniki czasowe - przydatne, jeśli napotkasz więcej niż jeden błąd w różnych momentach!

        try
        {
            context.SaveChanges();
        }
        catch (DbEntityValidationException e)
        {
            //Create empty list to capture Validation error(s)
            var outputLines = new List<string>();

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

5

Znalazłem ... kiedy dostaję błąd „EntityValidationErrors”, to… mam pole w mojej bazie danych „db1” w tabeli „tbladdress” jako „adres1”, który ma rozmiar 100 (tj. Adres varchar (100) null), a ja przekazywałam wartość ponad 100 znaków, co prowadziło do błędu podczas zapisywania danych w bazie danych ....

Musisz więc sprawdzić dane, które przekazujesz na pole.


1
Doceniam tę odpowiedź, ponieważ faktycznie pomogła mi rozwiązać mój błąd. Tabela, w której zapisywałem dane w bazie danych, zawierała wszystkie not nullkolumny, więc kiedy dodałem dane do wszystkich elementów przed moim, db.SaveChanges()nie otrzymałem błędu.
BinaryJoe01

3

To działa dla mnie.

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

Umieść punkt przerwania w instrukcji if. Następnie możesz sprawdzić modelState w oknach debugowania. Przy każdej wartości możesz zobaczyć, czy wystąpił błąd, a nawet komunikat o błędzie. Otóż ​​to. Kiedy już go nie potrzebujesz, po prostu usuń lub skomentuj wiersz.

Mam nadzieję, że to pomoże.

Na żądanie mogę podać szczegółowy zrzut ekranu w oknie debugowania.


3

Jak wspomniano w innych postach, wystarczy złapać wyjątek w klasie DbEntityValidationException. Co da ci wszystko, czego potrzebujesz w przypadkach błędów.

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

2

Wcześniej spotkałem się z tym błędem

kiedy próbowałem zaktualizować określone pole w moim modelu w ramach encji

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

i zgodnie z powyższymi odpowiedziami

Znalazłem komunikat Walidacja The SignerName field is required.

które wskazują na pole w moim modelu

a kiedy sprawdziłem schemat bazy danych, znalazłem

wprowadź opis zdjęcia tutaj

więc off coure ValidationExceptionma prawo podbić

i zgodnie z tym polem chcę, aby było zerowalne, (nie wiem jak to pomieszałem)

więc zmieniłem to pole, aby zezwolić na Null, i dzięki temu mój kod nie wyświetli mi tego błędu ponownie

więc ten błąd może się zdarzyć, jeśli unieważnisz integralność danych w bazie danych


1
Nie chodzi o to, czy należy podnieść wyjątek. Następnie skręcasz tutaj kilka rogów. Kiedy pole jest wymagane w schemacie bazy danych, potrzebujesz więcej niż to, aby mieć DbEntityValidationExceptionpodniesione.
Gert Arnold

2

Sprawdź przekazywaną wartość pól, czy są prawidłowe i zgodne z polami bazy danych. Na przykład liczba znaków przekazywanych w danym polu jest mniejsza niż liczba znaków zdefiniowanych w polu tabeli bazy danych.


1

Jeśli korzystasz z IIS z Windows Authentification and Entity Framework , bądź ostrożnyauthorize .

Starałem się POSTbez zgody i to nie działa, a ten błąd na db.SaveChangesAsync();, podczas gdy wszystkie inne czasowniki GETi DELETEpracowali.

Ale kiedy dodałem AuthorizeAttribute jako adnotację, zadziałało.

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

1

Oto inny sposób, aby to zrobić zamiast używać pętli foreach do wyszukiwania wewnątrz EntityValidationErrors. Oczywiście możesz sformatować wiadomość według własnych upodobań:

try {
        // your code goes here...
    } 
catch (DbEntityValidationException ex) 
    {
        Console.Write($"Validation errors: {string.Join(Environment.NewLine, ex.EntityValidationErrors.SelectMany(vr => vr.ValidationErrors.Select(err => $"{err.PropertyName} - {err.ErrorMessage}")))}", ex);
        throw;
    }

1

W moim przypadku było tak, ponieważ długość pola bazy danych jest mniejsza niż długość pola wejściowego.

tabela bazy danych

create table user(
  Username nvarchar(5) not  null
);

Mój wkład

User newUser = new User()
{
   Username = "123456"
};

wartość Username lengthwynosi 5, czyli lessthan6

... to może komuś pomóc


0

Sprawdź, czy masz Not Nullograniczenia w kolumnach tabeli i czy nie przekazujesz wartości dla tej kolumny podczas operacji wstawiania / aktualizacji. To powoduje ten wyjątek w strukturze encji.


0

Też napotkałem ten sam problem. Zaktualizowałem mój plik .edmx z bazy danych po tym, jak wyjątek zniknął.



0

Walczył również z tym błędem i na podstawie tematu tutaj i ta odpowiedź była w stanie wymyślić fragment do skopiowania / wklejenia bez potrzeby określania, co należy zaimportować (doskonałe dla początkujących w języku C #), kod poniżej:

try
{
  context.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException ex)
{
  foreach (var entityValidationErrors in ex.EntityValidationErrors)
  {
    foreach (var validationError in entityValidationErrors.ValidationErrors)
    {
      System.Diagnostics.Debug.WriteLine("Property: " + validationError.PropertyName + " Error: " + validationError.ErrorMessage);
    }
  }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.