web-dev-qa-db-ja.com

DbEntityValidationException - エラーの原因を簡単に判断する方法

Entity Frameworkを使用するプロジェクトがあります。私のSaveChangesDbContextを呼び出している間に、私は次の例外が出ます。

System.Data.Entity.Validation.DbEntityValidationException:1つ以上のエンティティの検証に失敗しました。詳細については、 'EntityValidationErrors'プロパティを参照してください。

これは大丈夫で面倒ですが、この例外が発生するたびにデバッガをアタッチする必要はありません。さらに、実稼働環境ではデバッガを簡単にアタッチできないため、これらのエラーを再現するには非常に長い努力が必要です。

DbEntityValidationException内に隠された詳細を見るにはどうすればいいですか?

210

最も簡単な解決策は、エンティティクラスのSaveChangesをオーバーライドすることです。あなたはDbEntityValidationExceptionをキャッチし、実際のエラーをアンラップし、そして改善されたメッセージで新しいDbEntityValidationExceptionを作成することができます。

  1. SomethingSomething.Context.csファイルの横に部分クラスを作成します。
  2. この記事の下部にあるコードを使用してください。
  3. それでおしまい。あなたの実装は、リファクタリング作業なしで自動的に上書きされたSaveChangesを使います。

あなたの例外メッセージは次のようになります。

System.Data.Entity.Validation.DbEntityValidationException:1つ以上のエンティティの検証に失敗しました。詳細については、 '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/

417

Martinが指摘したように、DbEntityValidationResultにはより多くの情報があります。それぞれのメッセージで私のPOCOクラス名とプロパティ名の両方を取得するのが便利で、このためだけにすべての[Required]タグにカスタムのErrorMessage属性を書く必要がないようにしたいと思いました。

以下のMartinのコードの微調整は、私にとってこれらの詳細の面倒を見ました:

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

EntityValidationErrorsコレクションを表示するには、次のWatch式を[Watch]ウィンドウに追加します。

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

私はビジュアルスタジオ2013を使っています

42
Shehab Fawzy

catch {...}ブロック内でデバッグモードに入っている間、 "QuickWatch"ウィンドウを開きます(ctrl+alt+q)を貼り付けます。

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

これにより、ValidationErrorsツリーにドリルダウンできます。それは私がこれらのエラーに対する即時の洞察を得るために私が見つけた最も簡単な方法です。

最初のエラーだけを気にしていて、catchブロックを持っていない可能性があるVisual 2012+ユーザーの場合は、次のようにすることもできます。

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

デバッグ中にエラーを調べて意味のあるエラーメッセージをすばやく見つけるには

  • クイックウォッチを追加する:

    ((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors
    
  • このようにEntityValidationErrorsにドリルダウンします。

    (コレクションアイテム[0])> ValidationErrors>(コレクションアイテム[0])> ErrorMessage

9
Chris Halcrow

実際には、これは単なる検証の問題であり、EFはデータベースに変更を加える前にまずエンティティのプロパティを検証します。そのため、テーブルを設計したときのように、EFはプロパティの値が範囲外かどうかを確認します。 Table_Column_UserNameはvarchar(20)です。しかし、EFでは、20より長い値を入力しました。あるいは、列がNULLになることを許可していない場合もあります。そのため、検証プロセスでは、変更を加えるかどうかにかかわらず、null以外の列に値を設定する必要があります。私は個人的には、Leniel Macaferiの回答が好きです。検証の問題の詳細を表示できます

5
Calvin

「実際の検証エラー」には機密情報が含まれている可能性があります。そのため、マイクロソフトはそれらを別の場所(プロパティ)に配置することを選択しました。ここでマークされた解決策は実用的ですが、慎重に行われるべきです。

私は拡張メソッドを作成したいと思います。これに対するさらなる理由:

  • 元のスタックトレースを保持する
  • オープン/クローズの原則に従います(つまり、ログの種類ごとに異なるメッセージを使用できます)。
  • 実稼働環境では、DbEntityValidationExceptionがスローされる可能性のある場所が他にもありました(例:other dbcontext)。
4
Luis Toapanta

Azure関数の場合は、この単純な拡張子をMicrosoft.Extensions.Logging.ILoggerに使用します。

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

次のようにコードでtryブロックを使用してください。

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. 1つ以上のエンティティの検証に失敗しました。詳細については 'EntityValidationErrors'プロパティを参照してください

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

0
Atta H.