[c#] فشل التحقق من الصحة لواحد أو أكثر من الكيانات أثناء حفظ التغييرات في قاعدة بيانات خادم SQL باستخدام Entity Framework



Answers

لا تغيير الرمز المطلوب:

أثناء وجودك في وضع التصحيح داخل كتلة catch {...} افتح النافذة "QuickWatch" ( Ctrl + Alt + Q ) والصق هناك:

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

أو:

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

إذا لم تكن في تجربة / تجربة أو لم يكن لديك حق الوصول إلى كائن الاستثناء.

سيسمح لك هذا ValidationErrors شجرة ValidationErrors . إنها الطريقة الأسهل التي وجدتها للحصول على إحصاءات فورية عن هذه الأخطاء.

Question

أرغب في حفظ تعديلي إلى قاعدة البيانات وأنا أستخدم كود Entity FrameWork الأول في ASP.NET MVC 3 / C # ولكنني أواجه أخطاء. في فئة الحدث الخاص بي ، لدي أنواع البيانات DateTime و TimeSpan ولكن في قاعدة البيانات الخاصة بي ، لقد حصلت على التاريخ والوقت على التوالي. يمكن أن يكون هذا هو السبب؟ كيف يمكنني الإرسال إلى نوع البيانات المناسب في التعليمة البرمجية قبل حفظ التغييرات في قاعدة البيانات.

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

طريقة في وحدة تحكم >>>> مشكلة في 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);
    }
}

مع

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

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

شكل المتشعب

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  

خطأ في الخادم في التطبيق '/'.

فشل التحقق من الصحة لواحد أو أكثر من الكيانات. راجع خاصية "EntityValidationErrors" لمزيد من التفاصيل.

الوصف: حدث استثناء غير معالج أثناء تنفيذ طلب الويب الحالي. الرجاء مراجعة تتبع التكديس للحصول على مزيد من المعلومات حول الخطأ وأين نشأ في التعليمة البرمجية.

تفاصيل الاستثناء: System.Data.Entity.Validation.DbEntityValidationException: فشل التحقق من الصحة لواحد أو أكثر من الكيانات. راجع خاصية "EntityValidationErrors" لمزيد من التفاصيل.

خطأ المصدر:

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

ملف المصدر: C: \ sep \ MvcEventCalendar \ MvcEventCalendar \ Controllers \ EventManagerController.cs الخط: 77

تتبع المكدس:

[DbEntityValidationException: فشل التحقق من الصحة لواحد أو أكثر من الكيانات. راجع خاصية "EntityValidationErrors" لمزيد من التفاصيل.]




تأكد من أنه إذا كان لديك nvarchar (50) في صف DB فأنت لا تحاول إدخال أكثر من 50 حرفًا في ذلك. خطأ غبي لكنه أخذني 3 ساعات لأكتشفه.




كتحسين لكل من برافين وتوني ، استخدم تجاوزًا:

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



هذا استثناء كيان التفاف التطبيق للاستثناء بنص التفاصيل. فإنه يعالج DbEntityValidationException ، DbUpdateException ، وأخطاء النطاق datetime2 (MS SQL) ، وتشمل مفتاح كيان غير صالح في الرسالة (مفيدة عند العديد من الكيانات SaveChanges استدعاء SaveChanges واحد).

أولاً ، تجاوز SaveChanges في فئة DbContext:

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

فئة الاستثناءات:

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



أنا لا أحب الاستثناءات سجلت OnSaveChanges ولدي هذا

var validationErrors = model.GetValidationErrors();

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



لقد واجهت نفس المشكلة قبل بضعة أيام أثناء تحديث قاعدة البيانات. في حالتي ، كان هناك عدد قليل من الأعمدة الجديدة غير القابلة للإضافة التي تمت إضافتها للصيانة والتي لم يتم توفيرها في التعليمة البرمجية التي تتسبب في الاستثناء. أجد تلك الحقول وأمدنا بها بالقيم وحللتها.




قد يحدث ذلك بسبب الخاصية التي لا يتم نشرها بالنموذج .. بدلاً من ذلك يتم ملؤها بواسطة وحدة التحكم .. والتي قد تتسبب في حدوث هذا الخطأ. حل هذا هو تعيين الخاصية قبل تطبيق التحقق من صحة ModelState. وهذا الافتراض الثاني هو. قد يكون لديك بالفعل بيانات في قاعدة البيانات الخاصة بك ومحاولة تحديثها ولكن الآن في جلبها.




أعتقد أن إضافة المحاولة / الالتقاط لكل عملية SaveChanges() ليست ممارسة جيدة ، فمن الأفضل إضفاء الطابع المركزي على هذا:

إضافة هذه الفئة إلى فئة DbContext الرئيسي:

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

سيؤدي هذا إلى استبدال طريقة SaveChanges() الخاصة SaveChanges() وستحصل على قائمة مفصولة بفواصل تحتوي على جميع أخطاء التحقق من الكيانات.

هذا أيضا يمكن أن تتحسن ، لتسجيل الأخطاء في env الإنتاج ، بدلاً من مجرد رمي خطأ.

أتمنى أن يكون هذا مفيدًا.




Related