156

I'm using Entity Framework code first in my website and I'm just wondering if there is any way to debug the migration codes. You know, like setting breakpoints and stuff like this.

I'm using Package Manager Console to update the database using Update-Database.

Thanks

Vahid Farahmandian
  • 6,081
  • 7
  • 42
  • 62
Daniel
  • 3,322
  • 5
  • 30
  • 40
  • It's just standard C# code - so yes, of course, you can set breakpoints in it..... – marc_s Jun 18 '13 at 12:40
  • 2
    but the application is not actually running since I'm using Package Manager Console. – Daniel Jun 18 '13 at 12:43
  • 1
    Then do not upgrade from Package manager console but set the migration initializer as the default initializer so that the database is migated the first time your application connects to it. – Wiktor Zychla Jun 18 '13 at 12:55
  • I'm updating my database by using the migration code and I can't stop the app and run it again to run the initializer. – Daniel Jun 18 '13 at 12:57
  • The reason I'm not using SQL is the code for the updating is rather complicated and it's almost impossible to implement it using SQL. – Daniel Jun 18 '13 at 12:58

7 Answers7

275

I know that EF Code First Migrations is relatively new tool but don't forget about you are still in .NET.

So you can use:

if (System.Diagnostics.Debugger.IsAttached == false)
{
    System.Diagnostics.Debugger.Launch();
}

After that you can see your InnerException.

Or you can use try...catch statement like this: Exception handling Entity Framework

Community
  • 1
  • 1
m_david
  • 3,207
  • 1
  • 17
  • 16
  • Thx m_david. I haven't had time to test this. I caught up in an android project. I'll test this when I have time to go back to my MVC website. – Daniel Jul 21 '13 at 04:02
  • 3
    Yes, this works while running an Update-Database through the package manager console. Very handy! – Tom Ferguson Jul 23 '13 at 09:45
  • 12
    I added this to the top of my Configuration.Seed method. It causes a popup that lets you select your Visual Studio to debug the code. However, my system hangs when I select it (perhaps unrelated). – Talon Sep 12 '13 at 09:21
  • 5
    Where to put this piece of code? if anyone can help out! Thanks. – Aritra B Feb 21 '14 at 09:57
  • 4
    In the constructor of your configuration class. – Casey Mar 05 '14 at 19:39
  • 5
    @Talon Go grab a coffee and by the time you're back probably another Visual Studio instance popped up. :) – Corstian Boerman Jun 17 '14 at 08:40
  • It's not what I meant but it sure helps. – Daniel Jul 04 '14 at 00:50
  • 2
    Can someone edit the answer to provide a complete solution as if they were explaining it to a rubber duck? (I'm about as smart as a rubber duck). E.g. 1) start the debugger. 2) set breakpoint 3.) add code to construtor, 4) run `update-database` in console, etc – Jeff Aug 04 '17 at 19:32
  • Great answer but It's worth noting that if you add this code to Seed method, compile, and then run migration *through migrate.exe utility* you'll actually get windows where you can choose the already opened Visual Studio and then debug there. However If you try to do migration in Visual Studio through "Package Manager Console" and "Update-Database" command you would only get option to open new Visual Studio. – Mariusz Pawelski Oct 23 '18 at 14:56
  • It is working fine, thank you! Note: It should be placed in the constructor of the context factory class (of type IDesignTimeDbContextFactory, where you have your `MyDbContext IDesignTimeDbContextFactory.CreateDbContext(string[] args)`) - and I suggest to surround it with `#if DEBUG ... (code from answer) ... #endif` to avoid having it in production deployments. You need to add that code only once, it activates subsequent breakpoints. – Matt Apr 27 '21 at 12:20
12

To hit a break point in a db migration set the context to MigrateDatabaseToLatestVersion on initialise.

Database.SetInitializer(new MigrateDatabaseToLatestVersion<EnterContextHere, Configuration>());

Then you just debug as normal (run using f5) and the breakpoint will hit the first time you run the project.

The problem now is that if you debug a second time the migration will not run. This is because the __MigrationHistory table has been updated to say you have migrated to the latest version. To re-test the migration open the package manager console and downgrade to the previous migration:

Update-Database –TargetMigration: ThePreviousMigrationName
robasaurus
  • 1,022
  • 8
  • 15
9

My answer might be a bit silly but anyway here it goes. If you, like me, some times have problems in the Seed() method what I usually do is simply create a public method that calls the Protect Seed().

public void SeedDebug(AppDbContext context)
{
    Seed(context);
}

then in my HomeController I call this method in Debug mode.

public class HomeController : Controller
{
    var appDb = new AppDbContext();
    public ActionResult Index()
    {
        var config = new Configuration();
        config.SeedDebug(appDb);
        return View();
    }
}

I know it's a bit lame solution, but it's simple and quick. Of course this has to be done after the model been created. So step by step:

  1. comment the seed method and execute the update-database to create the model
  2. uncomment the method Seed() and plugin the "hack" I mentioned above.

  3. in the configuration disable Auto migrations

    AutomaticMigrationsEnabled = false;//if you have this disabled already skip this step

  4. Debug your application, fix the error and remove the "hack"

Rui Lima
  • 7,185
  • 4
  • 31
  • 42
8

Here's a more fail-proof method which will do the trick without much fuss:

Step#1: Place this piece of code right above the migration you want to debug:

public partial class ORACLE_Test : DbMigration
{
    public override void Up()
    {
        if (!System.Diagnostics.Debugger.IsAttached)
            System.Diagnostics.Debugger.Launch();

        AddColumn("TEST", "UR_USER_ID", x => x.Decimal(nullable: false, precision: 11, scale: 0, storeType: "number"));
        AddColumn("TEST", "UR_CLIENT_ID", x => x.Decimal(nullable: false, precision: 11, scale: 0, storeType: "number"));
        [...]
    }

    public override void Down()
    {
    }
}

Step#2: Compile the project containing your migrations

Step#3: Open a console inside the output directory (/bin/Debug, /bin/Release etc) containing the dll of your migrations

Step#4: Invoke migrate.exe with the /scriptFile parameter to launch the debugger and actually debug the desired db-migration

migrate.exe "Your.Migrations.Assembly.dll" /scriptFile="foo.sql" /verbose /startupConfigurationFile="Your.Migrations.Assembly.config"

Once the debugger-selector dialog pops up pick the visual studio instance that you have already opened.

XDS
  • 3,786
  • 2
  • 36
  • 56
4

You could add Console.WriteLine statements to the migration code (not a great solution)

Note, the messages are only shown if you run the migration code using the migrate.exe utility (in pacakges\EntityFramework.x.y.z\tools). They will not display if you run the migration through the Package Manager console.

Mariusz Jamro
  • 30,615
  • 24
  • 120
  • 162
Tom Ferguson
  • 907
  • 1
  • 10
  • 26
2

I've had lots of luck using "Debugger.Launch()" (like in m_david's answer above) elsewhere, but inside of CreateDbContext it seems to somehow both attach, and not attach. What I mean is, it attaches and starts trying to step into .asm files and .cpp files (internal code). If I try to set a breakpoint on a Console.Writeline that I KNOW gets executed afterwards (I can see the output from ANY "dotnet ef migrations COMMAND") it both executes it and never hits the breakpoint.

This is what worked for me instead:

while (!System.Diagnostics.Debugger.IsAttached)
    System.Threading.Thread.Sleep(10);

// Breakpoint after this...

You can execute the migration and manually attach using Visual Studio and it will actually let you step through the code like you expect, it's just more of a pain. What I should really try is the combination of both methods...

0

I also found a neat trick here to get the error details...

Basically, the trick is to grab all the information from an exception, put it in a string and throw a new DbEntityValidationException with the generated string and the original exception.

ghigad
  • 341
  • 1
  • 12