Gỡ lỗi Bảng điều khiển Trình quản lý Gói Cập nhật-Phương pháp Hạt giống Cơ sở dữ liệu


106

Tôi muốn gỡ lỗi Seed()phương thức trong lớp cấu hình cơ sở dữ liệu Entity Framework của mình khi tôi chạy Update-Databasetừ Bảng điều khiển Trình quản lý Gói nhưng không biết cách thực hiện. Tôi muốn chia sẻ giải pháp với những người khác trong trường hợp họ gặp vấn đề tương tự.

Câu trả lời:


158

Đây là câu hỏi tương tự với một giải pháp hoạt động thực sự tốt.
Nó KHÔNG yêu cầu Thread.Sleep.
Chỉ cần khởi chạy trình gỡ lỗi bằng mã này.

Được cắt từ câu trả lời

if (!System.Diagnostics.Debugger.IsAttached) 
    System.Diagnostics.Debugger.Launch();

@tchelidze bạn có thể gọi migrate.exetừ bảng điều khiển để đính kèm studio trực quan hiện đang chạy. Xem thêm thông tin trong câu trả lời này: stackoverflow.com/a/52700520/350384
Mariusz Pawelski

20

Cách tôi giải quyết vấn đề này là mở một phiên bản mới của Visual Studio và sau đó mở cùng một giải pháp trong phiên bản Visual Studio mới này. Sau đó, tôi đã đính kèm trình gỡ lỗi trong phiên bản mới này với phiên bản cũ (devenv.exe) trong khi chạy lệnh update-database. Điều này cho phép tôi gỡ lỗi phương thức Seed.

Để đảm bảo rằng tôi không bỏ lỡ điểm ngắt do không đính kèm kịp thời, tôi đã thêm một Thread.Sleep trước điểm ngắt.

Tôi hi vọng điêu nay se giup được ai đo.


12

Nếu bạn cần lấy giá trị của một biến cụ thể, một cách nhanh chóng là đưa ra một ngoại lệ:

throw new Exception(variable);

3
Nhanh và bẩn :)
DanKodi

5

Một giải pháp rõ ràng hơn (tôi đoán điều này yêu cầu EF 6) IMHO sẽ gọi cập nhật-cơ sở dữ liệu từ mã:

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

Điều này cho phép bạn gỡ lỗi phương thức Seed.

Bạn có thể thực hiện bước này thêm một bước nữa và xây dựng một bài kiểm tra đơn vị (hoặc chính xác hơn là bài kiểm tra tích hợp) tạo cơ sở dữ liệu thử nghiệm trống, áp dụng tất cả các lần di chuyển EF, chạy phương pháp Seed và loại bỏ cơ sở dữ liệu thử nghiệm một lần nữa:

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

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

Database.Delete("TestDatabaseNameOrConnectionString");

Nhưng hãy cẩn thận để không chạy điều này với cơ sở dữ liệu phát triển của bạn!


1
Trong EF Core vì không có lớp DbMigrationsConfiguration, hãy sử dụng myDbContext.Database.GetPendingMigrations () để thay thế.
stevie_c

3

Tôi biết đây là một câu hỏi cũ, nhưng nếu tất cả những gì bạn muốn là tin nhắn và bạn không quan tâm đến việc bao gồm các tham chiếu đến WinForms trong dự án của mình, tôi đã tạo một số cửa sổ gỡ lỗi đơn giản để tôi có thể gửi các sự kiện Trace.

Để gỡ lỗi từng bước và nghiêm trọng hơn, tôi sẽ mở một phiên bản Visual Studio khác, nhưng nó không cần thiết đối với những thứ đơn giản.

Đây là toàn bộ mã:

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

Và trên Configuration.cs tiêu chuẩn của bạn

// ...
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!")
      // ...
    }
  }
}

1
Tất nhiên, cửa sổ gỡ lỗi có thể phức tạp như bạn muốn (thậm chí bạn có thể sử dụng trình thiết kế để tạo một biểu mẫu hoàn chỉnh và chuyển nó xung quanh để SeedInternalphương pháp có thể sử dụng nó)
Jcl


0

Tôi có 2 cách giải quyết (không có Debugger.Launch()vì nó không hiệu quả với tôi):

  1. Để in thông báo trong Bảng điều khiển Trình quản lý Gói, hãy sử dụng ngoại lệ:
    throw new Exception("Your message");

  2. Một cách khác là in thư trong tệp bằng cách tạo một cmdquy trình:


    // 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);
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.