Search code examples
c#entity-frameworkentity-framework-coreef-database-firstef-core-6.0

EF Core 6 startup project doesn't reference EFCore.Design while trying to scaffold to a project that is NOT the startup project


I have a Web API solution with several projects inside it. Tests, Services, Domain, Data and the API. The API project is the startup project. All of my EFCore references are in the Data project.

I am trying to run Scaffold-DbContext on the Data project however because it's not the startup project I'm getting the following error:

Your startup project 'APIProj' doesn't reference Microsoft.EntityFrameworkCore.Design. This package is required for the Entity Framework Core Tools to work. Ensure your startup project is correct, install the package, and try again.

The API project shouldn't know anything about EF Core so I don't want to just slap that reference in there and call it a day. Trying to do things better than they were... I also don't want to make anyone else who uses this to have to juggle startup projects. This should be simple.

How do I correctly point the Scaffold-DbContext command at a specific project regardless of what is the startup project.


Solution

  • Using the EF tools requires an executable project, So you'd either need to add that assembly to the executable project like you're suggesting yourself, or you can add a dummy executable project.

    See for ex;

    Why is a dummy project required? As mentioned earlier, the tools have to execute application code at design time. To do that, they need to use the .NET Core runtime. When the EF Core model is in a project that targets .NET Core or .NET Framework, the EF Core tools borrow the runtime from the project. They can't do that if the EF Core model is in a .NET Standard class library. The .NET Standard is not an actual .NET implementation; it's a specification of a set of APIs that .NET implementations must support. Therefore .NET Standard is not sufficient for the EF Core tools to execute application code. The dummy project you create to use as startup project provides a concrete target platform into which the tools can load the .NET Standard class library.

    https://learn.microsoft.com/en-us/ef/core/cli/dotnet#other-target-frameworks

    In our own project structure we have the design reference included in our executable project aswell. However, now that i'm thinking about this, our app gets rather large, and running the EF commands forces a rebuild of the executable project, so this means it will completely rebuild my large app which takes a long time.

    Therefore I recommend using a dummy project, like MSDN also recommends.

    Edit;

    I think in theory you could also make your data project an executable project, and reference that instead:

    // ConsoleApp1
    new MyConsoleApp2Class().Print();
    
    // ConsoleApp2
    namespace ConsoleApp2;
    
    public class MyConsoleApp2Class
    {
        public void Print()
        {
            Console.WriteLine("Hello world.");
        }
    }
    

    enter image description here

    This does output the exe in your /bin however: enter image description here

    This depends on the framework of your data project, .net standard projects cannot become executables.

    You can then use a Design time db context factory to help instantiate the db context for the tools (with the right sql connection string and so on):

    https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli#from-a-design-time-factory

    That way you don't need your data project to contain a whole application, as described in https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli#from-application-services

    The advantages of using the executable project of your app is that you can maintain appsettings for 1 project, the other approaches you'd have to save the connectiong string in 2 places, or have some logic in the design time factory to fetch the right connection string or something along those lines.

    But then again how often does your db connection string change? In most cases almost never.