DbEntityValidationException - मैं आसानी से कैसे बता सकता हूं कि त्रुटि का कारण क्या है?


217

मेरे पास एक प्रोजेक्ट है जो एंटिटी फ्रेमवर्क का उपयोग करता है। SaveChangesअपने पर कॉल करते समय DbContext, मुझे निम्नलिखित अपवाद मिलते हैं:

System.Data.Entity.Validation.DbEntityValidationException: सत्यापन एक या अधिक संस्थाओं के लिए विफल हुआ। अधिक विवरण के लिए 'EntityValidationErrors' संपत्ति देखें।

यह सब ठीक है और बांका है, लेकिन मैं हर बार एक डिबगर संलग्न नहीं करना चाहता हूं क्योंकि यह अपवाद होता है। अधिक से अधिक, उत्पादन वातावरण में मैं आसानी से डिबगर संलग्न नहीं कर सकता हूं, इसलिए मुझे इन त्रुटियों को पुन: उत्पन्न करने के लिए महान लंबाई पर जाना होगा।

मैं किस विवरण को भीतर छिपा हुआ देख सकता हूं DbEntityValidationException?

जवाबों:


430

सबसे आसान उपाय यह है SaveChangesकि आप अपने एंटिटीज़ क्लास को ओवरराइड करें। आप DbEntityValidationExceptionवास्तविक त्रुटियों को पकड़ सकते हैं, और DbEntityValidationExceptionबेहतर संदेश के साथ एक नया बना सकते हैं ।

  1. अपनी SomeSomething.Context.cs फ़ाइल के बगल में एक आंशिक वर्ग बनाएँ।
  2. इस पोस्ट के नीचे दिए गए कोड का उपयोग करें।
  3. बस। आपका कार्यान्वयन स्वचालित रूप से बिना किसी रिफलेक्टर के काम के ओवरराइड सेवचेंज का उपयोग करेगा।

आपका अपवाद संदेश अब इस तरह दिखेगा:

System.Data.Entity.Validation.DbEntityValidationException: सत्यापन एक या अधिक संस्थाओं के लिए विफल हुआ। अधिक विवरण के लिए 'EntityValidationErrors' संपत्ति देखें। सत्यापन त्रुटियां हैं: फ़ील्ड PhoneNumber में एक स्ट्रिंग या सरणी प्रकार होना चाहिए जिसकी अधिकतम लंबाई '12' है; LastName फ़ील्ड आवश्यक है।

आप किसी भी वर्ग में ओवरराइड किए गए SaveChanges को इनहेरिट कर सकते हैं DbContext:

public partial class SomethingSomethingEntities
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (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);
    
            // Throw a new DbEntityValidationException with the improved exception message.
            throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
        }
    }
}

DbEntityValidationExceptionभी संस्थाएं जो सत्यापन त्रुटियों की वजह से होता है। इसलिए यदि आपको और भी अधिक जानकारी की आवश्यकता है, तो आप इन संस्थाओं के बारे में जानकारी के लिए उपरोक्त कोड को बदल सकते हैं।

इन्हें भी देखें: http://devillers.nl/improving-dbentityvalidationexception/


6
जनरेट की गई एंटिटी क्लास पहले से ही DbContext से विरासत में मिली है, इसलिए आपको इसे आंशिक वर्ग पर फिर से नहीं जोड़ना है। आप इसे आंशिक वर्ग में जोड़कर किसी चीज को तोड़ेंगे या नहीं बदलेंगे। वास्तव में, यदि आप DbContext से विरासत को जोड़ते हैं, तो Resharper आपको इसे हटाने का सुझाव देगा: "आधार प्रकार 'DbContext' पहले से ही अन्य भागों में विशिष्ट है।"
मार्टिन डेविलर्स

15
यह SaveChanges का डिफ़ॉल्ट व्यवहार क्यों नहीं है?
जॉन शेडलेटस्की

4
"यह SaveChanges का डिफ़ॉल्ट व्यवहार क्यों नहीं है?" - यह एक बहुत अच्छा सवाल है। यह एक अद्भुत समाधान था, इसने मुझे घंटों बचाया! मैं करने के लिए में फेंक दिया थाusing System.Linq;
जॉन अगस्त

1
आधार पर मेरी क्रिएट व्यू एरर।सेवेचेंज () जो कि ट्राई ब्लॉक में है। यह कभी भी पकड़ में नहीं आता है। मुझे सेवचेंज पर सवारी करने के लिए आपका कोड मिल गया है, लेकिन यह कभी भी कैच ब्लॉक में त्रुटि पर नहीं आता है।
जस्टजॉन

7
स्टैक ट्रेस को संरक्षित करने के लिए आपको आंतरिक अपवाद सेट करना चाहिए।
डॉटजॉइ २oe

48

जैसा कि मार्टिन ने संकेत दिया है, इसमें अधिक जानकारी है DbEntityValidationResult। मैंने अपने प्रत्येक संदेश में अपने POCO वर्ग का नाम और संपत्ति का नाम दोनों को प्राप्त करना उपयोगी पाया, और इसके लिए ErrorMessageअपने सभी [Required]टैग पर कस्टम विशेषताएँ लिखने से बचना चाहता था ।

मार्टिन के कोड के निम्नलिखित ट्विक ने मेरे लिए इन विवरणों का ध्यान रखा:

// Retrieve the error messages as a list of strings.
List<string> errorMessages = new List<string>();
foreach (DbEntityValidationResult validationResult in ex.EntityValidationErrors)
{
    string entityName = validationResult.Entry.Entity.GetType().Name;
    foreach (DbValidationError error in validationResult.ValidationErrors)
    {
        errorMessages.Add(entityName + "." + error.PropertyName + ": " + error.ErrorMessage);
    }
}

1
का प्रयोग SelectMany and Aggregateमें GitHub द्वारा बहादुर Coders
Kiquenet

43

EntityValidationErrorsसंग्रह देखने के लिए, घड़ी विंडो में निम्न वॉच अभिव्यक्ति जोड़ें।

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

मैं दृश्य स्टूडियो 2013 का उपयोग कर रहा हूं


$ अपवाद शानदार है! इसका मतलब यह है कि तत्काल विंडो में मैं $ अपवाद कर सकता हूं। अनंतता अमान्यकरण। क्रमानुसार (x => x.ValidationErrors)। चुनाव (x => x.ErrorMessage);
chrispepper1989

13

जब आप catch {...}ब्लॉक में डिबग मोड में होते हैं, तो "क्विकवेच" विंडो ( ctrl+ alt+ q) खोलें और वहां पेस्ट करें:

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

यह आपको नीचे ड्रिल करने की अनुमति देगा ValidationErrors पेड़ । इन त्रुटियों में त्वरित जानकारी प्राप्त करना सबसे आसान तरीका है।

दृश्य 2012+ उपयोगकर्ताओं के लिए जो केवल पहली त्रुटि की परवाह करते हैं और उनमें कोई catchब्लॉक नहीं हो सकता है , आप भी कर सकते हैं:

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

9

डीबगिंग के दौरान त्रुटि का निरीक्षण करके एक सार्थक त्रुटि संदेश को जल्दी से खोजने के लिए:

  • इसके लिए एक त्वरित घड़ी जोड़ें:

    ((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
  • इस तरह EntityValidationErrors में नीचे ड्रिल करें:

    (संग्रह आइटम उदा [0])> सत्यापन शुल्क> (संग्रह आइटम उदा [0])> त्रुटि संग्रह


5

वास्तव में, यह केवल सत्यापन का मुद्दा है, EF डेटाबेस में कोई भी बदलाव करने से पहले पहले इकाई के गुणों को मान्य करेगा। इसलिए, ईएफ यह जांच करेगा कि क्या संपत्ति का मूल्य सीमा से बाहर है, जैसे आपने टेबल डिज़ाइन किया था। Table_Column_UserName varchar (20) है। लेकिन, EF में, आपने 20 से अधिक समय के लिए एक मान दर्ज किया है। या, अन्य मामलों में, यदि स्तंभ शून्य होने की अनुमति नहीं देता है। इसलिए, सत्यापन प्रक्रिया में, आपको शून्य स्तंभ पर कोई मान सेट करना होगा, चाहे आप उस पर परिवर्तन करने जा रहे हों। मैं व्यक्तिगत रूप से, लेनियल मैकफेरी जवाब की तरह। यह आपको सत्यापन मुद्दों का विवरण दिखा सकता है


4

मुझे लगता है कि "वास्तविक सत्यापन त्रुटियों" में संवेदनशील जानकारी हो सकती है, और यही कारण हो सकता है कि Microsoft ने उन्हें किसी अन्य स्थान (गुण) पर रखने का विकल्प चुना। यहां चिह्नित समाधान व्यावहारिक है, लेकिन इसे सावधानी के साथ लिया जाना चाहिए।

मैं एक विस्तार विधि बनाना पसंद करूंगा। इसके और कारण:

  • मूल स्टैक ट्रेस रखें
  • खुले / बंद सिद्धांत का पालन करें (यानी: मैं विभिन्न प्रकार के लॉग के लिए विभिन्न संदेशों का उपयोग कर सकता हूं)
  • उत्पादन वातावरण में अन्य स्थान हो सकते हैं (जैसे: अन्य dbcontext) जहां एक DbEntityValidationException को फेंक दिया जा सकता है।

1

Azure Functions के लिए हम Microsoft के लिए इस सरल एक्सटेंशन का उपयोग करते हैं

public static class LoggerExtensions
{
    public static void Error(this ILogger logger, string message, Exception exception)
    {
        if (exception is DbEntityValidationException dbException)
        {
            message += "\nValidation Errors: ";
            foreach (var error in dbException.EntityValidationErrors.SelectMany(entity => entity.ValidationErrors))
            {
                message += $"\n * Field name: {error.PropertyName}, Error message: {error.ErrorMessage}";
            }
        }

        logger.LogError(default(EventId), exception, message);
    }
}

और उदाहरण के उपयोग:

try
{
    do something with request and EF
}
catch (Exception e)
{
    log.Error($"Failed to create customer due to an exception: {e.Message}", e);
    return await StringResponseUtil.CreateResponse(HttpStatusCode.InternalServerError, e.Message);
}

0

अपने कोड में कोशिश ब्लॉक का उपयोग करें

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

आप यहाँ भी विवरण देख सकते हैं

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

  2. सत्यापन एक या अधिक संस्थाओं के लिए विफल रहा। अधिक विवरण के लिए 'EntityValidationErrors' संपत्ति देखें

  3. http://blogs.infosupport.com/improving-dbentityvalidationexception/


आप तीसरा लिंक स्वीकृत उत्तर के ब्लॉग की एक प्रति है, लेकिन एक अलग साइट पर। दूसरा लिंक एक स्टैक ओवरफ्लो प्रश्न है जो पहले से ही आपके पहले लिंक को संदर्भित करता है।
एरिस

तो, उचित संदर्भ के साथ किसी की मदद करने की कोशिश करना यहां कोई मुद्दा है?
एटा एच।

हां, आपके उत्तर में सिर्फ लिंक नहीं होना चाहिए। एक सारांश बनाएं जो प्रश्न का उत्तर देता है और फिर किसी भी आगे पढ़ने के लिए लिंक को पोस्ट करें।
क्रिस 10
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.