Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Command Exception: No executable name found matching command "dotnet-ef" #9

Closed
ilmax opened this issue Jun 6, 2016 · 22 comments
Closed

Comments

@ilmax
Copy link

ilmax commented Jun 6, 2016

Hi, when using EF6 in a core class library, after running the command e.g. dotnet ef migrations enable, I'm hitting this exception:

Microsoft.DotNet.Cli.Utils.CommandUnknownException: No executable found matching command "dotnet-ef"

I've put together a small sample demonstrating the issue, you can find it here

Steps to repro

  • Clone
  • Compile
  • cd WebApp.Data
  • dotnet-ef migrations enable

Expected output:

Migrations enabled as expected

Actual output:

Unhandled Exception: Microsoft.DotNet.Cli.Utils.CommandUnknownException: No executable found matching command "dotnet-ef"
   at Microsoft.DotNet.Cli.Utils.ProjectDependenciesCommandFactory.FindProjectDependencyCommands(String commandName, IEnumerable`1 commandArgs, String configuration, NuGetFramework framework, String outputPath, String buildBasePath, String projectDirectory)
   at Microsoft.DotNet.Cli.Utils.ProjectDependenciesCommandFactory.Create(String commandName, IEnumerable`1 args, NuGetFramework framework, String configuration)
   at Microsoft.Extensions.Internal.DotnetToolDispatcher.CreateDispatchCommand(IEnumerable`1 dispatchArgs, NuGetFramework framework, String configuration, String outputPath, String buildBasePath, String projectDirectory, String toolName)
   at Microsoft.Extensions.Internal.DotnetToolDispatcher.CreateDispatchCommand(IEnumerable`1 dispatchArgs, NuGetFramework framework, String configuration, String outputPath, String buildBasePath, String projectDirectory)
   at Migrator.EF6.Tools.Program.Dispatch(String[] args)
   at Migrator.EF6.Tools.Program.Main(String[] args)

Please note that everything is working as expected if EF6 is placed in the startup application.

Am I missing something?

@mrahhal
Copy link
Owner

mrahhal commented Jun 7, 2016

@ilmax currently I'm not supporting scenarios beyond the migrations being in the startup app but someone claimed it worked for them a little while ago.

I'll try reproducing your repo and come back to you. If it doesn't really work maybe I'll add support for that. I've always wanted to but my migrations have always been in the startup app till now.

@mrahhal
Copy link
Owner

mrahhal commented Jun 7, 2016

@ilmax looks like this is a limitation right now (one hell of a limitation for people using library projects as a DAL with migrations).

Preview 1 Known Issues

.NET Core CLI does not support running commands on class libraries as of Preview 1. Despite being able to install EF tools, executing commands may throw this error message.

See here, dotnet/cli#2645 and dotnet/efcore#5460.

Keep in mind that you can always have a DAL project as a library but migrations should be in your app. That's my current configuration on an app running in production. And I'd say this is better than having migrations in a library.

Would you mind explaining why you want your migrations to be in the library instead of the app?

@ilmax
Copy link
Author

ilmax commented Jun 7, 2016

Thank you for the quick response. I found out that putting "emitentrypoint": true in the library's project.json did the trick (at least partially).

For migrations I like to keep in the same project just for "locality" purposes.

Will try your suggestion and come back here.

@ilmax ilmax closed this as completed Jun 7, 2016
@mrahhal
Copy link
Owner

mrahhal commented Jun 7, 2016

Nice! I'll be glad if you can come back to let me know what worked for you.

@sagoo33
Copy link

sagoo33 commented Jun 17, 2016

Hello, I also had this issue, and found that I also had to add a Program.cs with a main entry point and an initializer for the DataContext as well as putting "emitentrypoint": true in the project.json :

This is only used in development however, the main web project doesn't need this.

public class Program
{
    public static void Main(string[] args)
    {
    }
}

public class MigrationsContextFactory : IDbContextFactory<DAContext>
{
    public DAContext Create()
    {
        return new DAContext("sqlconnectionstring");
    }
}

@mrahhal
Copy link
Owner

mrahhal commented Jun 17, 2016

@sagoo33 so you just made your DAL project executable and you referenced it like always and it worked? Good to know!
Any drawbacks though or everything worked fine?

@sagoo33
Copy link

sagoo33 commented Jun 17, 2016

Yep, that's exactly what I did.
I could then run the migrations directly on the DAL via Migrator.EF6.

It did appear that I couldn't hit any breakpoints in the DAL after making it an executable...though I am unsure if it was due to this or something else.

@mrahhal
Copy link
Owner

mrahhal commented Jun 17, 2016

Oh, maybe that's what @ilmax meant by "partially".

@sagoo33 I myself have an app running in production and the migrations are with the app even though I have a DAL so I'm curious to know if there's a need for you in putting the migrations with your DAL instead of the app. Is there a reason you're doing that instead of just having the migrations be a part of the app instead?

@ilmax
Copy link
Author

ilmax commented Jun 17, 2016

@mrahhal exactly, you have to set emitEntryPoint to true only when running migrations and then revert it back.

@mrahhal
Copy link
Owner

mrahhal commented Jun 17, 2016

Ah now I get it. A little but annoying but if that works.

@ilmax is there a reason for not putting migrations in your app directly? (while keeping the DAL)

@ilmax
Copy link
Author

ilmax commented Jun 17, 2016

I have no time yet to try it out (currently working on another project). I will try it out as soon as possible and come back here as promised :)

@mrahhal
Copy link
Owner

mrahhal commented Jun 17, 2016

No pressure, I just thought there might be a reason but I guess both ways work equally :)

@joshgarwood
Copy link

joshgarwood commented Sep 1, 2016

Hi @mrahhal ! I wanted to quickly take a moment to answer your question as stated below:

"Is there a reason you're doing that instead of just having the migrations be a part of the app instead?"

My answer to that is to maintain a clear separation of concerns. In my opinion, the application/web project should never need to know anything about the database, or even a reference to EntityFramework... That's the entire purpose of a DAL, to abstract the interaction with the database out of the application. By putting migrations in the application itself, you lose the modularity of the project, and it becomes very tightly coupled to your DAL.

Perhaps I'm being overly pedantic about a having a clear separation of concerns, but putting database migrations inside of a web project feels wrong.

That said, I'm super grateful for this library and the tools it provides; it's unfortunate that Microsoft is making us jump through so many hoops to use EF6 in a core project, ha.

@mrahhal
Copy link
Owner

mrahhal commented Sep 1, 2016

@joshgarwood agreed. It's truly unfortunate that even now we still don't have a comfortable way to do what feels right. It's always workarounds around tooling and structuring, I said it before but I'm becoming more and more jealous of frameworks like rails that gets it right. sigh

Now for the problem at hand, I still didn't experiment with a solution due to lack of time but I might do that soon. I agree with your point about SOC, I myself can't sleep well at night knowing there is a better way that feels more "right". Alas, developers have to do what they have to do with the tooling they have, it's really annoying that the only thing standing in your way most of the time is the tooling. You can do little without tooling support and that's my main problem with how things are right now.

The thing is, I have to produce results (most of the time) so I'm currently using migrations inside my web app but I have a separate project that contains the models/entities (this sounds so wrong, I know).

@mrahhal
Copy link
Owner

mrahhal commented Sep 1, 2016

@joshgarwood by the way, I just remembered. Maybe you're already doing it and it's already mentioned above but here goes. You can workaround this and put migrations in your core by doing the following in your core project:

  • Add this in your project.json:
"buildOptions": {
  "emitEntryPoint": true
}
  • Add a static void Main() {} stub.

This will trick the tooling into thinking it's an app. After that you'll be able to use the dotnet ef command normally. And just add a reference to this project from your web app. I don't think there are side effects to this workaround, I just tested it too.

@joshgarwood
Copy link

@mrahhal Thank you so SO much! That worked perfectly for me. And many thanks for the detailed response; it was most helpful!

All the best!

@sagoo33
Copy link

sagoo33 commented Sep 7, 2016

The side effects come when you forget to set build options back to false ;)

"buildOptions": { "emitEntryPoint": false }

@mrahhal
Copy link
Owner

mrahhal commented Sep 7, 2016

@joshgarwood glad it worked!

@sagoo33 yup! I spent a bit of time before figuring this out. Since when you set emitEntryPoint to true, a .dll won't be emitted/copied to bin and your app might be referencing an older version of the library. That's what @ilmax meant by partially. We should only set it to true while running the migration commands.

Also, I opened an issue about this at dotnet/cli#4147 because I never found out if this behavior will change in a future version anywhere.

@mrahhal
Copy link
Owner

mrahhal commented Sep 7, 2016

The issue (of not being able to run tools in a Class Library) is documented here.

@DOTang
Copy link

DOTang commented Oct 5, 2016

Hi, thanks for this library. I am trying this and still get the same error:

dotnet : No executable found matching command "dotnet-ef"

My project JSON looks like this:

{
  "version": "1.0.0-*",

  "dependencies": {
    "EntityFramework": "6.1.3",
    "Migrator.EF6.Tools": "1.0.5",
    "NETStandard.Library": "1.6.0"
  },

  "frameworks": {
    "net461": {}
  },

  "buildOptions": {
    "emitEntryPoint": true
  }
}

and I made a program.cs file with:

public class Program
{
    static void Main() { }
}

I downloaded the package Migrator.EF6.Tools.

What am I doing wrong? I notice that package has dependency on .NET 451, but I am targeting 461, does that matter? I tried running this from package manager console and VS developer command prompt in the projects root directory, is this correct?

@mrahhal
Copy link
Owner

mrahhal commented Oct 6, 2016

@DOTang you can safely use libraries targeting a .NET version lower than your target version. What you're missing is the tools entry in your project.json. Please check the README here:

Make sure to update both entries inside dependencies and tools to the latest version.

Also, this is unrelated but you should remove NETStandard.Library from the dependencies section. Your project.json should look like this:

{
  ...

  "dependencies": {
    "EntityFramework": "6.1.3",
    "Migrator.EF6.Tools": {
      "type": "build",
      "version": "1.0.5"
    }
  },

  "tools": {
    "Migrator.EF6.Tools": {
      "imports": "portable-net45+win8+dnxcore50",
      "version": "1.0.5"
    }
  },

  ...
}

@DOTang
Copy link

DOTang commented Oct 6, 2016

Thank you, that did it. I saw that and added that in there at some point, but somehow I deleted it in my fidgeting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants