it-swarm.asia

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

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

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 قاعدة البيانات/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" لمزيد من التفاصيل.]

330
user522767

يمكنك استخراج جميع المعلومات من DbEntityValidationException بالكود التالي (تحتاج إلى إضافة مساحات الأسماء: System.Data.Entity.Validation و System.Diagnostics إلى قائمة using):

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

لا يلزم تغيير الرمز:

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

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

أو:

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

إذا لم تكن في موقع try/catch أو لا يمكنك الوصول إلى كائن الاستثناء.

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

248
GONeale

في حالة وجود فئات لها نفس أسماء الممتلكات ، إليك ملحق صغير لإجابة برافين:

 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

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

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

هذا الاستثناء التفاف كيان التنفيذ إلى استثناء مع نص التفاصيل. يعالج أخطاء النطاق DbEntityValidationException ، DbUpdateException ، datetime2 (MS SQL) ، ويتضمن مفتاح الكيان غير الصحيح في الرسالة (مفيد عند استحضار العديد من الكيانات في مكالمة واحدة 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);
        }
    }

فئة ExceptionHelper:

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

ساعد هذا الرمز في العثور على مشكلتي عندما واجهت مشكلة مع Entity VAlidation Erros. لقد أخبرتني المشكلة بالضبط في تعريف الكيان الخاص بي. حاول اتباع التعليمات البرمجية حيث تريد تغطية storeDB.SaveChanges ()؛ في محاولة التالية كتلة الصيد.

  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;
}
5
Рахул Маквана

كنت أتلقى هذا الخطأ اليوم ولم أتمكن من حل المشكلة لفترة من الوقت ، لكنني أدركت أنه بعد إضافة بعض RequireAttributes إلى النماذج الخاصة بي وأن بعض البيانات الأولية للتطوير لم تملأ جميع الحقول المطلوبة.
لذا ، لاحظ فقط أنه إذا تلقيت هذا الخطأ أثناء تحديث قاعدة البيانات من خلال نوع من استراتيجية التهيئة مثل DropCreateDatabaseIfModelChanges ، فيتعين عليك التأكد من أن بياناتك الأولية تفي وتلبي أي سمات للتحقق من صحة بيانات النموذج .

أعلم أن هذا يختلف قليلاً عن المشكلة في السؤال ، لكنه سؤال شائع لذا اعتقدت أنني سأضيف أكثر قليلاً إلى الإجابة بالنسبة للآخرين الذين لديهم نفس المشكلة مثل نفسي.
آمل أن يساعد هذا الآخرين :)

4
dan richardson

أعتقد أن إضافة تجربة/تجربة لكل عملية 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() الخاص بالسياق وستحصل على قائمة مفصولة بفواصل تحتوي على جميع أخطاء التحقق من الكيان.

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

آمل أن يكون هذا مفيدًا.

4
Chtiwi Malek

إليك امتدادًا لملحق Tony ... :-)

بالنسبة إلى Entity Framework 4.x ، إذا كنت ترغب في الحصول على اسم وقيمة حقل المفتاح بحيث تعرف مثيل الكيان (سجل DB) الذي يواجه المشكلة ، يمكنك إضافة ما يلي. يوفر هذا الوصول إلى أعضاء الفئة ObjectContext أكثر قوة من كائن DbContext الخاص بك.

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

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

var validationErrors = model.GetValidationErrors();

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

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

2
user4030144

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

2
laylarenee

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

1
JM Kumawat

قد يكون هذا بسبب الحد الأقصى لعدد الأحرف المسموح بها لعمود معين ، كما هو الحال في الحقل sql واحد قد يتبع نوع البيانات nvarchar(5) ولكن عدد الأحرف التي تم إدخالها من المستخدم أكبر من المحدد ، وبالتالي ينشأ الخطأ.

1
lokopi

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

0
Muhammad Mustafa

شكراً لإجاباتك ، ساعدني كثيرًا. كما أنا رمز في Vb.Net ، هذا رمز بولت ل 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

في حالتي لدي اسم عمود الجدول ، المسار الذي حددته هو varchar (200). بعد تحديثه إلى nvarchar (بحد أقصى) ، قمت بحذف الجدول من edmx ثم أضفته مرة أخرى إلى الجدول و wokred بشكل صحيح بالنسبة لي.

0
Saket Singh