223

Entity Framework を使用するプロジェクトがあります。を呼び出すSaveChangesDbContext、次の例外が発生します。

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

これはすべてうまくいきますが、この例外が発生するたびにデバッガーをアタッチしたくありません。さらに、実稼働環境では、デバッガーを簡単に接続できないため、これらのエラーを再現するために多大な労力を費やす必要があります。

内に隠されている詳細を確認するにはどうすればよいDbEntityValidationExceptionですか?

4

9 に答える 9

437

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/

于 2013-04-04T19:54:47.010 に答える
49

マーティンが指摘したように、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);
    }
}
于 2013-10-07T16:31:26.647 に答える
45

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

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

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

于 2015-08-09T09:52:57.177 に答える
14

ブロック内でデバッグ モードになっている間に、 [QuickWatch] ウィンドウ ( + + ) をcatch {...}開き、そこに貼り付けます。ctrlaltq

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

ValidationErrorsこれにより、ツリーをドリルダウンできます。これらのエラーを即座に把握するには、これが最も簡単な方法です。

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

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors.First().ValidationErrors.First().ErrorMessage
于 2016-03-14T23:26:35.997 に答える
10

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

  • 以下のクイック ウォッチを追加します。

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

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

于 2016-10-20T00:21:54.483 に答える
6

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

于 2016-10-26T23:14:04.787 に答える
5

「実際の検証エラー」には機密情報が含まれている可能性があると思います。これが、Microsoft がそれらを別の場所 (プロパティ) に配置することを選択した理由である可能性があります。ここで示した解決策は実用的ですが、注意して実行する必要があります。

拡張メソッドを作成したいと思います。これに対するその他の理由:

  • 元のスタック トレースを保持する
  • オープン/クローズの原則に従います (つまり、ログの種類ごとに異なるメッセージを使用できます)。
  • 本番環境では、DbEntityValidationException がスローされる可能性のある他の場所 (つまり、他の dbcontext) が存在する可能性があります。
于 2015-08-18T22:07:14.870 に答える
2

Azure Functions では、 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);
}
于 2018-03-15T16:27:15.073 に答える