128

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

エンティティ フレームワーク (4.1.3) のコード ファースト アプローチ用にクラスを定義しました。シードを開始するまでは、すべて問題ありませんでした (テーブルなどを作成していました)。

今私がするとき

Add-Migration "remigrate" ; Update-Database;

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

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

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

4

6 に答える 6

218

私も最近これに悩まされました。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)

于 2012-05-20T19:32:59.223 に答える
118

すでに部分的なクラス定義を使用して 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 } 

部分クラスの全体的な考え方 -- DbContext が部分クラスあることに気付きましたか -- 生成されたクラスを拡張する (または複数のファイルにクラスを整理する) ことができ、私たちの場合はSaveChangesメソッドもオーバーライドしたいということです。DbContextに追加する部分クラス内から。

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

これが私がすることです(違いは、生成されたものではなく、独自に作成されたDbContext部分クラスでSaveChangesメソッドをオーバーライドするだけであることに注意してください)。また、部分クラスが正しい名前空間を使用していることを確認してください。そうしないと、頭を壁にぶつけることになります。

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
        }
    }
}
于 2013-03-31T06:18:55.080 に答える
36

Richards の回答を拡張メソッドに変換しました。

  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();
于 2013-03-12T21:46:02.530 に答える
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());
}
于 2012-10-26T16:52:39.523 に答える
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

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

于 2012-10-26T00:56:30.943 に答える