Debugging Package Manager Console Update-Database Seed Method

106

Saya ingin men-debug Seed()metode di kelas konfigurasi database Entity Framework saya saat menjalankan Update-Databasedari Package Manager Console tetapi tidak tahu cara melakukannya. Saya ingin berbagi solusi dengan orang lain jika mereka memiliki masalah yang sama.

Sachin Kainth
sumber

Jawaban:

158

Berikut pertanyaan serupa dengan solusi yang bekerja dengan sangat baik.
Itu TIDAK membutuhkan Thread.Sleep.
Luncurkan saja debugger menggunakan kode ini.

Dipotong dari jawabannya

if (!System.Diagnostics.Debugger.IsAttached) 
    System.Diagnostics.Debugger.Launch();
EthR
sumber
@tchelidze Anda dapat memanggil migrate.exedari konsol untuk melampirkan studio visual yang sedang berjalan. Info MOre dalam jawaban ini: stackoverflow.com/a/52700520/350384
Mariusz Pawelski
20

Cara saya memecahkan ini adalah dengan membuka contoh baru Visual Studio dan kemudian membuka solusi yang sama dalam contoh baru Visual Studio ini. Saya kemudian memasang debugger dalam contoh baru ini ke contoh lama (devenv.exe) saat menjalankan perintah update-database. Ini memungkinkan saya untuk men-debug metode Seed.

Hanya untuk memastikan saya tidak melewatkan breakpoint dengan tidak melampirkan waktu, saya menambahkan Thread.Sleep sebelum breakpoint.

Saya harap ini membantu seseorang.

Sachin Kainth
sumber
12

Jika Anda perlu mendapatkan nilai variabel tertentu, cara cepatnya adalah dengan membuat pengecualian:

throw new Exception(variable);
cederlof.dll
sumber
3
Cepat dan kotor :)
DanKodi
5

Solusi yang lebih bersih (saya kira ini membutuhkan EF 6) adalah IMHO akan memanggil database pembaruan dari kode:

var configuration = new DbMigrationsConfiguration<TContext>();
var databaseMigrator = new DbMigrator(configuration);
databaseMigrator.Update();

Ini memungkinkan Anda untuk men-debug metode Seed.

Anda dapat mengambil satu langkah lebih jauh dan membuat pengujian unit (atau, lebih tepatnya, pengujian integrasi) yang membuat database pengujian kosong, menerapkan semua migrasi EF, menjalankan metode Seed, dan menghapus database pengujian lagi:

var configuration = new DbMigrationsConfiguration<TContext>();
Database.Delete("TestDatabaseNameOrConnectionString");

var databaseMigrator = new DbMigrator(configuration);
databaseMigrator.Update();

Database.Delete("TestDatabaseNameOrConnectionString");

Namun berhati-hatilah agar tidak menjalankan ini pada database pengembangan Anda!

Jesper Mygind
sumber
1
Di EF Core karena tidak ada kelas DbMigrationsConfiguration, gunakan myDbContext.Database.GetPendingMigrations () sebagai gantinya.
stevie_c
3

Saya tahu ini adalah pertanyaan lama, tetapi jika yang Anda inginkan hanyalah pesan, dan Anda tidak peduli untuk menyertakan referensi ke WinForms dalam proyek Anda, saya membuat jendela debug sederhana tempat saya dapat mengirim peristiwa Trace.

Untuk debugging yang lebih serius dan selangkah demi selangkah, saya akan membuka instance Visual Studio lain, tetapi tidak perlu untuk hal-hal sederhana.

Ini adalah keseluruhan kode:

SeedApplicationContext.cs

using System;
using System.Data.Entity;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;

namespace Data.Persistence.Migrations.SeedDebug
{
  public class SeedApplicationContext<T> : ApplicationContext
    where T : DbContext
  {
    private class SeedTraceListener : TraceListener
    {
      private readonly SeedApplicationContext<T> _appContext;

      public SeedTraceListener(SeedApplicationContext<T> appContext)
      {
        _appContext = appContext;
      }

      public override void Write(string message)
      {
        _appContext.WriteDebugText(message);
      }

      public override void WriteLine(string message)
      {
        _appContext.WriteDebugLine(message);
      }
    }

    private Form _debugForm;
    private TextBox _debugTextBox;
    private TraceListener _traceListener;

    private readonly Action<T> _seedAction;
    private readonly T _dbcontext;

    public Exception Exception { get; private set; }
    public bool WaitBeforeExit { get; private set; }

    public SeedApplicationContext(Action<T> seedAction, T dbcontext, bool waitBeforeExit = false)
    {
      _dbcontext = dbcontext;
      _seedAction = seedAction;
      WaitBeforeExit = waitBeforeExit;
      _traceListener = new SeedTraceListener(this);
      CreateDebugForm();
      MainForm = _debugForm;
      Trace.Listeners.Add(_traceListener);
    }

    private void CreateDebugForm()
    {
      var textbox = new TextBox {Multiline = true, Dock = DockStyle.Fill, ScrollBars = ScrollBars.Both, WordWrap = false};
      var form = new Form {Font = new Font(@"Lucida Console", 8), Text = "Seed Trace"};
      form.Controls.Add(tb);
      form.Shown += OnFormShown;
      _debugForm = form;
      _debugTextBox = textbox;
    }

    private void OnFormShown(object sender, EventArgs eventArgs)
    {
      WriteDebugLine("Initializing seed...");
      try
      {
        _seedAction(_dbcontext);
        if(!WaitBeforeExit)
          _debugForm.Close();
        else
          WriteDebugLine("Finished seed. Close this window to continue");
      }
      catch (Exception e)
      {
        Exception = e;
        var einner = e;
        while (einner != null)
        {
          WriteDebugLine(string.Format("[Exception {0}] {1}", einner.GetType(), einner.Message));
          WriteDebugLine(einner.StackTrace);
          einner = einner.InnerException;
          if (einner != null)
            WriteDebugLine("------- Inner Exception -------");
        }
      }
    }

    protected override void Dispose(bool disposing)
    {
      if (disposing && _traceListener != null)
      {
        Trace.Listeners.Remove(_traceListener);
        _traceListener.Dispose();
        _traceListener = null;
      }
      base.Dispose(disposing);
    }

    private void WriteDebugText(string message)
    {
      _debugTextBox.Text += message;
      Application.DoEvents();
    }

    private void WriteDebugLine(string message)
    {
      WriteDebugText(message + Environment.NewLine);
    }
  }
}

Dan pada Configuration.cs standar Anda

// ...
using System.Windows.Forms;
using Data.Persistence.Migrations.SeedDebug;
// ...

namespace Data.Persistence.Migrations
{
  internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
  {
    public Configuration()
    {
      // Migrations configuration here
    }

    protected override void Seed(MyContext context)
    {
      // Create our application context which will host our debug window and message loop
      var appContext = new SeedApplicationContext<MyContext>(SeedInternal, context, false);
      Application.Run(appContext);
      var e = appContext.Exception;
      Application.Exit();
      // Rethrow the exception to the package manager console
      if (e != null)
        throw e;
    }

    // Our original Seed method, now with Trace support!
    private void SeedInternal(MyContext context)
    {
      // ...
      Trace.WriteLine("I'm seeding!")
      // ...
    }
  }
}
Jcl
sumber
1
Tentu saja, jendela debug dapat menjadi serumit yang Anda inginkan (Anda bahkan dapat menggunakan desainer untuk membuat formulir lengkap dan menyebarkannya sehingga SeedInternalmetode dapat menggunakannya)
Jcl
1

Uh Debugging adalah satu hal tetapi jangan lupa untuk memanggil: konteks.Update ()

Juga jangan membungkus try catch tanpa pengecualian internal yang baik ke konsol.
https://coderwall.com/p/fbcyaw/debug-into-entity-framework-code-first dengan tangkapan (DbEntityValidationException ex)

Steven Packham
sumber
Silakan periksa URL ini. Ini akan berguna untuk meningkatkan kualitas konten Anda
Willie Cheng
0

Saya memiliki 2 solusi (tanpa Debugger.Launch()karena itu tidak berhasil untuk saya):

  1. Untuk mencetak pesan di Package Manager Console menggunakan pengecualian:
    throw new Exception("Your message");

  2. Cara lain adalah mencetak pesan dalam file dengan membuat cmdproses:


    // Logs to file {solution folder}\seed.log data from Seed method (for DEBUG only)
    private void Log(string msg)
    {
        string echoCmd = $"/C echo {DateTime.Now} - {msg} >> seed.log";
        System.Diagnostics.Process.Start("cmd.exe", echoCmd);
    }
Gendolph
sumber