Paket Yöneticisi Konsolu Hata Ayıklama Güncelleme-Veritabanı Tohum Yöntemi


106

Paket Yöneticisi Konsolu'ndan Seed()çalıştırdığımda Update-Databaseancak nasıl yapılacağını bilmediğimde Entity Framework veritabanı yapılandırma sınıfımdaki yöntemde hata ayıklamak istedim . Aynı sorunu yaşarlarsa çözümü başkalarıyla paylaşmak istedim.

Yanıtlar:


158

İşte gerçekten iyi çalışan bir çözümle benzer bir soru .
Gerektirmez Thread.Sleep.
Sadece bu kodu kullanarak hata ayıklayıcıyı başlatır.

Cevaptan kısaltıldı

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

@tchelidze migrate.exeşu anda çalışan görsel stüdyosunu eklemek için konsoldan arayabilirsiniz . Bu cevapta daha fazla bilgi: stackoverflow.com/a/52700520/350384
Mariusz Pawelski

20

Bunu çözme şeklim, yeni bir Visual Studio örneği açmak ve ardından aynı çözümü bu yeni Visual Studio örneğinde açmaktı. Daha sonra güncelleme-veritabanı komutunu çalıştırırken bu yeni örnekteki hata ayıklayıcıyı eski örneğe (devenv.exe) ekledim. Bu, Seed yönteminde hata ayıklamamı sağladı.

Zamanında ekleme yapmayarak kesme noktasını kaçırmadığımdan emin olmak için, kesme noktasından önce bir Thread.Sleep ekledim.

Umarım bu birine yardımcı olur.


12

Belirli bir değişkenin değerini almanız gerekiyorsa, hızlı bir hack bir istisna atmaktır:

throw new Exception(variable);

3
Hızlı ve kirli :)
DanKodi

5

Daha temiz bir çözüm (sanırım bu EF 6 gerektirir) IMHO'nun koddan güncelleme veritabanını çağırması olacaktır:

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

Bu, Tohum yönteminde hata ayıklamanıza olanak tanır.

Bunu bir adım daha ileri götürebilir ve boş bir test veritabanı oluşturan, tüm EF geçişlerini uygulayan, Seed yöntemini çalıştıran ve test veritabanını yeniden düşüren bir birim testi (veya daha doğrusu bir entegrasyon testi) oluşturabilirsiniz:

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

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

Database.Delete("TestDatabaseNameOrConnectionString");

Ancak bunu geliştirme veritabanınızda çalıştırmamaya dikkat edin!


1
EF Core'da DbMigrationsConfiguration sınıfı olmadığından bunun yerine myDbContext.Database.GetPendingMigrations () kullanın.
stevie_c

3

Bunun eski bir soru olduğunu biliyorum, ancak tek istediğiniz mesajlarsa ve projenize WinForms referansları eklemek istemiyorsanız, İzleme olaylarını gönderebileceğim bazı basit hata ayıklama penceresi yaptım.

Daha ciddi ve adım adım hata ayıklama için başka bir Visual Studio örneği açacağım, ancak basit şeyler için gerekli değil.

Kodun tamamı bu:

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

Ve standart Configuration.cs dosyanızda

// ...
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
Elbette, hata ayıklama penceresi istediğiniz kadar karmaşık olabilir (tam bir form oluşturmak için tasarımcıyı bile kullanabilir ve SeedInternalyöntemin kullanabilmesi için onu etrafta geçirebilirsiniz )
Jcl


0

2 geçici çözümüm var ( Debugger.Launch()benim için çalışmadığından):

  1. Paket Yöneticisi Konsolunda mesaj yazdırmak için istisna kullanın:
    throw new Exception("Your message");

  2. Başka bir yol da bir cmdişlem oluşturarak mesajı dosyaya yazdırmaktır :


    // 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);
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.