Entity Framework kullanılarak SQL Server Veritabanında değişiklikler kaydedilirken bir veya daha fazla varlık için doğrulama başarısız oldu


337

Benim veritabanına Düzenle kaydetmek istiyorum ve ASP.NET MVC 3 / C # varlık FrameWork kod ilk kullanıyorum ama hata alıyorum. Event sınıfımda DateTime ve TimeSpan veri türlerine sahibim ancak veritabanımda sırasıyla Tarih ve saat var. Nedeni bu olabilir mi? Veritabanındaki değişiklikleri kaydetmeden önce koddaki uygun veri tipine nasıl başvurabilirim.

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

Denetleyicideki yöntem >>>> storeDB.SaveChanges () sorunu

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

ile

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 Veritabanı / T-SQL

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

Http Formu

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  

'/' Uygulamasında Sunucu Hatası

Bir veya daha fazla varlık için doğrulama başarısız oldu. Daha fazla ayrıntı için 'EntityValidationErrors' özelliğine bakın.

Açıklama: Geçerli web isteğinin yürütülmesi sırasında işlenmeyen bir özel durum oluştu. Hata ve kodun nereden kaynaklandığı hakkında daha fazla bilgi için lütfen yığın izlemesini inceleyin.

Özel Durum Ayrıntıları: System.Data.Entity.Validation.DbEntityValidationException: Bir veya daha fazla varlık için doğrulama başarısız oldu. Daha fazla ayrıntı için 'EntityValidationErrors' özelliğine bakın.

Kaynak Hatası:

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

Kaynak Dosya: C: \ sep \ MvcEventCalendar \ MvcEventCalendar \ Controllers \ EventManagerController.cs Satır: 77

Yığın izleme:

[DbEntityValidationException: Bir veya daha fazla varlık için doğrulama başarısız oldu. Daha fazla ayrıntı için 'EntityValidationErrors' özelliğine bakın.]


8
muhtemelen zorunlu alanlarınızdan birinin değeri sıfırdır. EventDate, StartTime, Fiyat, Kategori vb. Gibi
Daveo

Her birinin veritabanı tanımlı türle eşleştiğinden emin olmak için gönderilen form değişkenlerini incelediniz mi? Ya da Daveo'nun söylediği gibi, gerekli form değerlerinden biri eksik ...
timothyclifford

Gönderilen form değişkenlerinin tümü veritabanı tanımlı türle eşleşmiyor. Veritabanında tarih ve saat kullandım ancak .NET'te doğrudan veri türü eşdeğeri yoktur. Bu nedenle DateTime ve TimeSpan kullandım. Şimdi ikisini sırasıyla tarih ve saate dönüştürmem gerekiyor.
user522767

Benim için hatanın kaynağı 30'dan fazla karakterden oluşan bir dize alanıydı ve veritabanımdaki alan
boyutum 30'du

Yanıtlar:


840

Tüm bilgileri DbEntityValidationException aşağıdaki kodla (: İsim alanlarının eklemeleri gerekir System.Data.Entity.Validationve System.Diagnosticssizin için usinglisteden):

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

7
Herhangi bir tohum verisi model özniteliği kurallarını (örneğin Required) tam olarak karşılamıyorsa da bu hatayı alabilirsiniz . Biraz daha bilgi içeren bir cevap ekledim.
dan richardson

8
İzleme çıktısını gerçekte nerede görebileceğiniz açıklanarak cevap geliştirilebilir.
mkataja

1
İz ile ilgili bu msdn makalesini çok faydalı buldum
Borik

2
Siz efendim, interneti kazandınız.
Leandro

8
Trace çıktısı Çıktı penceresinde görülebilir. Üst
taraftaki

249

Kod değişikliği gerekmez:

catch {...}Blok içinde hata ayıklama modundayken "QuickWatch" penceresini ( Ctrl+ Alt+ Q) açın ve buraya yapıştırın:

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

veya:

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

Bir try / catch uygulamasında değilseniz veya istisna nesnesine erişiminiz yoksa.

Bu, ValidationErrorsağaca inmenizi sağlar. Bu hataları anında anlamanın en kolay yolu.


6
Sen benim arkadaşım bir dahisin, aldığım ET hatasını takip etmeme yardım ettin, teşekkürler!
Mark Kram

4
Sorun değil :) Ama bir dahi değil, sadece QuickWatch'u seviyorum :)
GONeale

4
İstisna nesnesine / değişkenine erişimi olmayanların cevabını güncelledik.
GONeale

7
Bu istisnayı her aldığımda hatayı ararım, o zaman buraya geliyorum (Google'da 2. sonuç), bu gönderiyi buluyorum ve Hata ayıklama> İzleme panelindeki ikinci çözümü kullanıyorum. Düzinelerce kez yaptı. Teşekkür ederim GONeale.
Ata S.

1
İkinci sorguyu çalıştırırken "Şu anki bağlamda '$ exception' adı yok" adını alan tek kişi ben miyim?
Alex Klaus

37

Aynı mülk adlarına sahip sınıflarınız varsa, işte Praveen'in cevabının küçük bir uzantısı:

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

22

Hem Praveen hem de Tony için bir iyileştirme olarak, bir geçersiz kılma kullanıyorum:

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

6

Bu uygulama, ayrıntı metniyle istisna için varlık istisnasını kaydırır. O kolları DbEntityValidationException, DbUpdateException, datetime2aralık hataları (MS SQL) ve (mesajında birinde kullanışlı zaman savind sayıda öğe geçersiz varlığın anahtarı bulunurSaveChanges çağrı).

İlk olarak, SaveChangesDbContext sınıfında geçersiz kılma :

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 sınıfı:

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

İstisnayı işlemek istiyorsanız SaveChangesAsync çağrısını beklemelisiniz.
Arnab Chakraborty

Teşekkürler, Arnab Chakraborty ! Yanıt düzeltildi
Sel

5

Bu kod, Varlık VAlidation Erros ile sorun yaşadığımda sorunumu bulmamda yardımcı oldu. Varlık Tanımımla ilgili tam sorunu anlattı. StoreDB.SaveChanges (); aşağıdaki catch bloğunu deneyin.

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

4

Bugün bu hatayı alıyordum ve bir süre çalışamadım, ancak RequireAttributemodellerime biraz s ekledikten ve bazı geliştirme tohumu verilerinin gerekli alanların tümünü doldurmadığını fark ettim .
Bu nedenle, veritabanını bu tür bir başlangıç ​​stratejisi aracılığıyla güncellerken bu hatayı alıyorsanız DropCreateDatabaseIfModelChanges, tohum verilerinizin herhangi bir model veri doğrulama özelliğini yerine getirdiğinden ve karşıladığından emin olmanız gerektiğini unutmayın .

Bunun sorudaki sorundan biraz farklı olduğunu biliyorum, ancak popüler bir soru, bu yüzden kendimle aynı sorunu olan başkaları için cevaba biraz daha ekleyeceğimi düşündüm.
Umarım bu başkalarına yardımcı olur :)


4

Bence her biri için dene / yakala SaveChanges() işlem iyi bir uygulama olmadığını , bunu merkezileştirmek daha iyidir:

Bu sınıfı ana DbContextsınıfa ekleyin :

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

Bu, bağlamınızın üzerine yazacaktır SaveChanges() yönteminin ve tüm varlık doğrulama hatalarını içeren virgülle ayrılmış bir liste alacaksınız.

bu sadece bir hata atmak yerine env'deki hataları günlüğe kaydetmek için de geliştirilebilir.

umarım bu yardımcı olur.


"DbContext Class" ı nerede bulabilirim? Ben tüm bu MVC şeyler biraz yeniyim. MVC 5 ve Entity Framework 6 kullanıyorum. Çözüm Gezgini'nde adın ne olmasını istediğini bilmiyorum.
JustJohn

@JJJohn veritabanı modelinizde (sınıf dosyası), nerede olduğunu bilmiyorsanız DbContext, projenize karşı anahtar kelimenin tam bir aramasını yapabilirsiniz .
Chtiwi Malek

1
Uygulamada evrensel bir çözüm olduğu ve sistemdeki diğer modüller için çok fazla değişmeden yüzeyin altında ne olduğunu kolayca ortaya çıkardığı için bu yaklaşımı en çok
seviyorum

3

İşte Tony'nin uzantısı ... :-)

Entity Framework 4.x için, hangi varlık örneğinin (DB kaydı) sorunun olduğunu bilmeniz için anahtar alanının adını ve değerini almak istiyorsanız, aşağıdakileri ekleyebilirsiniz. Bu, DbContext nesnenizden daha güçlü ObjectContext sınıfı üyelerine erişim sağlar.

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

İstisnaları sevmiyorum OnSaveChanges'i kaydettirdim ve buna sahibim

var validationErrors = model.GetValidationErrors();

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

"OnSaveChanges'i kaydettim" derken ne demek istiyorsun?
Akira Yamamoto

Bağlamdaki OnSaveChanges'e diğerleriyle aynı şekilde bağlandım, sadece istisna aşamasına ulaşmadım. \
Mickey Perlstein

2

Bu hata, doğrulama hataları olan bir varlığı kaydetmeye çalıştığınızda da oluşur. Bunun nedeninin iyi bir yolu, DB'nize kaydetmeden önce ModelState.IsValid'i kontrol etmeyi unutmaktır.


2

DB satırında nvarchar (50) varsa, içine 50'den fazla karakter eklemeye çalışmadığınızdan emin olun. Aptalca bir hata ama çözmem 3 saatimi aldı.


1

Bunun nedeni, belirli bir sütun için izin verilen maksimum karakter sayısından kaynaklanıyor olabilir, örneğin sql'de bir alan aşağıdaki Veri Türüne sahip olabilir, nvarchar(5)ancak kullanıcıdan girilen karakter sayısı belirtilenden fazladır, bu nedenle hata ortaya çıkar.


1

Veritabanını güncellerken birkaç gün önce aynı sorunla karşılaştım. Benim durumumda, istisnaya neden olan kodda sağlanmayan bakım için null edilemeyen birkaç yeni sütun eklendi. Bu alanları ve verilen değerleri çözdüm ve çözdüm.


0

Cevaplarınız için thnaks, bana çok yardımcı oluyor. Vb.Net'te i kodu olarak, Vb.Net için bu Bolt kodu

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

bunun nedeni model tarafından doldurulmamış Özellik olabilir .. bunun yerine Denetleyici tarafından doldurulur .. bu hataya neden olabilir .. Bu çözüm ModelState doğrulaması uygulanmadan önce özelliği atar. ve bu ikinci Varsayım. Veritabanınızda zaten Veri var ve güncellemeye çalışıyor olabilirsiniz, ancak şimdi getiriliyor.


0

Benim durumumda ben set veri türü varchar (200) olan bir Tablo Sütun adı Yolu var. Nvarchar (max) güncelledikten sonra, tablo edmx sildi ve sonra tekrar tablo ekledi ve benim için düzgün uyandım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.