EFコードファースト:nugetパッケージコンソールから「EntityValidationErrors」プロパティを表示するにはどうすればよいですか?


127

私はこれで途方に暮れています:

エンティティフレームワーク(4.1.3)のコードを最初に使用するためのクラスを定義しました。シードを始めるまでは、すべてが順調でした(テーブルを作成していたなど)。

今私が行うとき

Add-Migration "remigrate" ; Update-Database;

パッケージコンソールで「1つ以上のエンティティの検証に失敗しました。詳細については、「EntityValidationErrors」プロパティを参照してください。」というエラーが表示されます。

Seed()メソッドにブレークポイントがありますが、プロジェクトが実行されていないときにコンソールでこれを実行しているため、詳細に到達する方法については無知です(PS-スレッドの検証が失敗したことを確認しましたEntity Framework使用してSQL Serverデータベースへの変更を保存している間に1つ以上のエンティティが表示され、プロパティの表示方法が示されます。)

Seed()メソッドに問題があることは知っています。メソッド呼び出しの直後にreturnを置くと、エラーがなくなるためです。では、検証エラーを確認できるようにブレークポイントを設定するにはどうすればよいですか?ちょっと負けました。または、nugetコンソールでそれをトレースする他の方法はありますか?


クイックアップデート:エラーの原因を見つけるまで、メソッド内の各変数を体系的に追跡することで問題を解決しました。ただし、質問への回答がはるかに速くなるので、それでも知りたいです。
ジェレミー

プログラムで移行を実行し、例外をキャッチしてエラーを繰り返すことができると思います。理想的ではありませんが、必要な詳細が得られる場合があります。
パヴェル

間違った答えが答えの一番上にあり、すべての信用を得たときにイライラする。StackOverflowが明らかに不足している場所!
jwize

回答:


216

私も最近これに悩まされました。SeedメソッドのConfigurationクラスにラッパー関数を配置して修正SaveChangesし、代わりにへの呼び出しを関数への呼び出しに置き換えました。この関数は、単にEntityValidationErrorsコレクション内のエラーを列挙し、例外メッセージに個々の問題がリストされている例外を再スローします。これにより、出力がNuGetパッケージマネージャーコンソールに表示されます。

コードは次のとおりです。

/// <summary>
/// Wrapper for SaveChanges adding the Validation Messages to the generated exception
/// </summary>
/// <param name="context">The context.</param>
private void SaveChanges(DbContext context) {
    try {
        context.SaveChanges();
    } catch (DbEntityValidationException ex) {
        StringBuilder sb = new StringBuilder();

        foreach (var failure in ex.EntityValidationErrors) {
            sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType());
            foreach (var error in failure.ValidationErrors) {
                sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
                sb.AppendLine();
            }
        }

        throw new DbEntityValidationException(
            "Entity Validation Failed - errors follow:\n" + 
            sb.ToString(), ex
        ); // Add the original exception as the innerException
    }
}

ちょうどに呼び出しを置き換えるcontext.SaveChanges()SaveChanges(context)、あなたのシード方法で。


リチャード、ついに!アイデアを持っている人。もう一度試してみると、この質問に戻ります。
ジェレミー

これは本当に厄介な問題を追跡するのに役立ちます:)
エミネム

3
この手法を使用しましたが、代わりにコンテキスト内のsavechangesのオーバーライドを使用しました。public override int SaveChanges() コンテキスト内。
Kirsten Greed

5
以下で答えたように、部分クラスを使用するとより効果的です。
jwize 2014年

1
シードメソッドでUserManager操作を実行している場合、この変更の出力に検証エラーは含まれません。@ jwizeの回答に従って、DBContext SaveChanges、SaveChangesAsync、およびSaveChangesAsync(CT)メソッドをオーバーライドする必要があります。
カール・

115

部分的なクラス定義でDBContextクラスを拡張してください!

DbContextのクラス定義を見ると、次のようになります。

// DatabaseContext.cs   -- This file is auto generated and thus shouldn't be changed. 
public partial class [DatabaseContextName] : DbContext { ... }

したがって、別のファイルで同じ定義を作成し、必要な部分をオーバーライドできます。

// partialDatabaseContext.cs  -- you can safely make changes 
// that will not be overwritten in here.
public partial class [DatabaseContextName] : DbContext { // Override defaults here } 

部分クラスとの全体的なアイデアは、あなたが気づく--did DbContextは、部分的class--であるあなたは、生成されたクラスを拡張(または複数のファイルにクラスを編成する)ことができるということですし、我々の場合には、我々はまたしたい上書きのSaveChangesメソッドをDbContextに追加する部分クラス内から。

このようにして、既存のすべてのDbContext / SaveChanges呼び出しからエラーデバッグ情報をどこでも取得でき、シードコードや開発コードをまったく変更する必要がありません。

これは私が何をするのか(あるNOTEの違いは、私はちょうど私たち自身でSaveChangesメソッドが執筆オーバーライドすることであるDbContext部分クラス、しないで生成したワンを)。また、部分クラスが正しい名前空間を使用していることを確認してください。そうしないと、壁に頭をぶつけてしまいます。

public partial class Database : DbContext
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();
        }
        catch (DbEntityValidationException ex)
        {
            var sb = new StringBuilder();

            foreach (var failure in ex.EntityValidationErrors)
            {
                sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType());
                foreach (var error in failure.ValidationErrors)
                {
                    sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
                    sb.AppendLine();
                }
            }

            throw new DbEntityValidationException(
                "Entity Validation Failed - errors follow:\n" +
                sb.ToString(), ex
                ); // Add the original exception as the innerException
        }
    }
}

あなたは天才です...!
フロリアンF.

素晴らしいソリューション。投票する前に、すべての回答を読む必要があります。
Guilherme de Jesus Santos

3
また、SaveChangesAsyncとSaveChangesAsync(CancellationToken)もオーバーライドする必要があります-少なくともコードが最初の場合はそうですが、最初にモデル/データベースについては不明です。
Carl

@jwize。あなたの答えは私のデータベースで最初に例外処理の問題をモデル化するのに役立ちました。すばらしい答え
3355307

1
CodeFirstを使用する場合、DbContextは明らかに生成されません。ただし、デザイナーを使用すると、DbContextクラスとEntityクラスが生成され、部分クラスを使用してオーバーライドする必要があります。
jwize 2016年

35

リチャーズの回答を拡張メソッドに変換しました:

  public static int SaveChangesWithErrors(this DbContext context)
    {
        try
        {
            return context.SaveChanges();
        }
        catch (DbEntityValidationException ex)
        {
            StringBuilder sb = new StringBuilder();

            foreach (var failure in ex.EntityValidationErrors)
            {
                sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType());
                foreach (var error in failure.ValidationErrors)
                {
                    sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
                    sb.AppendLine();
                }
            }

            throw new DbEntityValidationException(
                "Entity Validation Failed - errors follow:\n" +
                sb.ToString(), ex
            ); // Add the original exception as the innerException
        }
    }

このように呼び出します:

context.SaveChangesWithErrors();

4

craigvlのバージョンをC#に変換しました。context.SaveChanges();を追加する必要がありました。それが以下のように私のために働くために。

try
{
    byte[] bytes = System.IO.File.ReadAllBytes(@"C:\Users\sheph_000\Desktop\Rawr.png");
    Console.WriteLine(bytes);

    context.BeverageTypes.AddOrUpdate(
        x => x.Name,
        new AATPos.DAL.Entities.BeverageType { ID = 1, Name = "Sodas" }
        );

    context.Beverages.AddOrUpdate(
        x => x.Name,
        new AATPos.DAL.Entities.Beverage { ID = 1, Name = "Coke", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" },
        new AATPos.DAL.Entities.Beverage { ID = 2, Name = "Fanta", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" },
        new AATPos.DAL.Entities.Beverage { ID = 3, Name = "Sprite", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" },
        new AATPos.DAL.Entities.Beverage { ID = 4, Name = "Cream Soda", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" },
        new AATPos.DAL.Entities.Beverage { ID = 5, Name = "Pepsi", BeverageTypeID = 1, ImageData = bytes, IsStocked = true, StockLevel = 10, Price = 10.00M, ImageMimeType = "test" }
        );

    context.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException ex)
{
    var sb = new System.Text.StringBuilder();
    foreach (var failure in ex.EntityValidationErrors)
            {
                sb.AppendFormat("{0} failed validation", failure.Entry.Entity.GetType());
        foreach (var error in failure.ValidationErrors)
                {
            sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
            sb.AppendLine();
                }
            }

    throw new Exception(sb.ToString());
}

3

以下の正しいパス(同じ問題を抱えていました)に導いてくれたリチャードは、移行構成シードメソッドでこれが機能するラッパーなしの代替手段です。

 Protected Overrides Sub Seed(context As NotificationContext)

        Try
            context.System.AddOrUpdate(
               Function(c) c.SystemName,
                New E_NotificationSystem() With {.SystemName = "System1"},
                New E_NotificationSystem() With {.SystemName = "System2"},
                New E_NotificationSystem() With {.SystemName = "System3"})

            context.SaveChanges()

        Catch ex As DbEntityValidationException

            Dim sb As New StringBuilder

            For Each failure In ex.EntityValidationErrors

                sb.AppendFormat("{0} failed validation" & vbLf, failure.Entry.Entity.[GetType]())

                For Each [error] In failure.ValidationErrors
                    sb.AppendFormat("- {0} : {1}", [error].PropertyName, [error].ErrorMessage)
                    sb.AppendLine()
                Next
            Next

            Throw New Exception(sb.ToString())

        End Try
End Sub

その後、パッケージマネージャーコンソールで例外を確認できました。これが誰かを助けることを願っています。


-1

I Also had same model validation problem but successfully catch by myself after lot of thinking;

I use reverse engineering method to catch the problem out of Over 80 + Model Classes;

1> Made copy of dbcontext, changing the name (I add "1" at end and make respective changes in class constructor and initialization etc.

Old:
 
>public class AppDb : IdentityDbContext<ApplicationUser>
>     
> {
> public AppDb(): base("DefaultConnection", throwIfV1Schema: false)
> {
> 
> }
>     
> public static AppDb Create()
>{
>return new AppDb();
>} 

**New:**

>public class AppDb1 : IdentityDbContext<ApplicationUser>
>{
>public AppDb1()
>: base("DefaultConnection", throwIfV1Schema: false)
>{
>}
> 
>public static AppDb1 Create()
> {
> return new AppDb1();
>  }`

...
2> Make changes to Codefirst Migration Configuration from Old DbContext to my new Context.

> internal sealed class Configuration :
> DbMigrationsConfiguration<DAL.AppDb1> { public Configuration() {
> AutomaticMigrationsEnabled = false; }    protected override void
> Seed(DAL.AppDb1 context) {`

3> Comment the Dbsets in new DbContext which was doubt.
4> Apply update migration if succeeded the probelm lye in Commented section.
5> if not then commented section is clear of bug clear.
6> repeat the (4) until found the right place of bug.
7> Happy Codding


1
コードをフォーマットするときに、テキストがコードブロック内にないようにするとよいでしょう。
jmattheis

これはおそらく私が今まで見た中で最悪のフォーマットされたstackoverflowの答えである
crazy_crank
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.