Can't add Entity Framework Core migrations to

2019-03-01 13:17发布

问题:

I've got a Solution with many projects. One of them (Domain) is a .NET Standard 2.0 project where I made my EF Core DbContext implementation for which I want to enable database migrations.

I saw various blogs and Q/A forums where the problem was explained but none of the proposed solutions seem to work for me because of the .NET Core newer version or (probably) for my particular solution configuration.

Solution projects

  • Engine (.NET Core 2.1 Console App)
  • Web API (.NET Core 2.1 Library)
  • Application (.NET Core 2.1 Library)
  • Domain (.NET Standard 2.0 Library)
  • WindowsService (.NET Core 2.1 Console App)

The WindowsService is the Startup project, where an instance of the Engine is created and encapsulated to run as Windows Service or Console application (for debug).

The Engine is the real core application, where an instance of Kestrel self-host Web server is configured as Web API and instantieted. Also other components are instantiated and stay alive (UDP listener, machine watchdog, etc...).

WebAPI has Startup class but no Program class, since all the configuration and the Web server start is done inside Engine.Program.cs class.

Dependencies

  • WindowsService => Engine
  • Engine => WebAPI
  • WebAPI => Application, Domain
  • Application => Domain

The first attempt was to simply launch add-migration Initial from PMC with Domain project as target, but it turns to:

Unable to create an object of type 'MyDbContext'. Add an implementation of 'IDesignTimeDbContextFactory' to the project, or see https://go.microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time.

Then I followed the proposed solution on this question, but:

  1. add-migration Initial from PMC, after setting My WebAPI (with no Program class) as startup project, turns to:

    It was not possible to find any compatible framework version The specified framework 'Microsoft.NETCore.App', version '2.1.0' was not found.

    • Check application dependencies and target a framework version installed at: C:\Program Files\dotnet\
    • Installing .NET Core prerequisites might help resolve this problem: http://go.microsoft.com/fwlink/?LinkID=798306&clcid=0x409
    • The .NET Core framework and SDK can be installed from: https://aka.ms/dotnet-download
    • The following versions are installed: 2.0.5 at [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] 2.0.6 at [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] 2.0.7 at [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] 2.0.9 at [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] 2.1.2 at [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  2. add-migration Initial from PMC, after adding an additional target framework (netcoreapp2.1) to the Domain library project file, leads me to the same error as the 1st attempt.

  3. add-migration Initial from PMC, after adding a reference to Microsoft.EntityFrameworkCore.SqlServer.Design v1.1.6 always leads to same error as the 1st attempt.

What should I do?

UPDATE

This is the new Domain.csproj file after removing the unecessary libraries references.

<ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.1" />
    <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>

All libraries in all projects are up to date.

回答1:

  1. Download and install appropriate Runtime and SDK from here - I guess you need .NET Core 2.1.302 at the moment
  2. Microsoft.EntityFrameworkCore.SqlServer.Design is not needed anymore as it's included to SDK. CLI reference in csproj fiels for EntityFrameworkCore is not needed as well.
  3. Make sure you Manage NuGet packages window shows all updated.
  4. Add anywhere in you web project implementation of IDesignTimeDbContextFactory interface - it will be found automatically and used for EF Add-Migration (or dotnet ef... analogues) command in Package Manager Console

    public class DesignTimeActivitiesDbContextFactory : IDesignTimeDbContextFactory<ActivitiesDbContext>
    {
        public ActivitiesDbContext CreateDbContext(string[] args)
        {
            DbContextOptionsBuilder<ActivitiesDbContext> builder = new DbContextOptionsBuilder<ActivitiesDbContext>();
    
            var context = new ActivitiesDbContext(
                builder
                .UseSqlServer("Data Source=(local)\LocalDB;Initial Catalog=DB_name;Integrated Security=True;")
                .Options);
    
            return context;
        }
    }
    

To read the connection string from your appsettings config file you could do the following:

public class DesignTimeActivitiesDbContextFactory : IDesignTimeDbContextFactory<ActivitiesDbContext>
{
    public ActivitiesDbContext CreateDbContext(string[] args)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(Path.Combine(Directory.GetCurrentDirectory()))
            .AddJsonFile("appsettings.Development.json", optional: false);

        var config = builder.Build();

        var optionsBuilder = new DbContextOptionsBuilder<ActivitiesDbContext>()
            .UseSqlServer(config.GetConnectionString("DefaultConnection"));

        return new ActivitiesDbContext(optionsBuilder.Options);
    }
}

NOTE: in the above code factory will use connection string value defined in appsettings.Development.json file. And connection name is DefaultConnection. In other words, this disign time factory is used for the Code First commands like Add-Migration, Update-Database, etc...) and will apply them to the database connection configured for Development environment.



回答2:

Your csproj file for the class library should contain at least this package. Make sure your versions match for all your Microsoft packages. Either 2.1.0 or 2.1.1 (latest at this time)

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.1" />
  </ItemGroup>

</Project>

In the Package Manager Console, set your default project set to the class library where you want the migrations. It's a drop down in the top right of the console window. Also, make sure your start-up project is the project that has the database connection info.

If the start-up project doesn't have an instance of the DbContext you are wanting to scaffold, you will get the error because it doesn't know how to materialize a DbContext. You should have the DbContext registered in your Startup.cs like this:

services.AddDbContext<MyDbContext>(options => options.UseSqlServer(connectionString));

Then, run the command Add-Migration InitialCreate. This will scaffold your migration, it should add a folder to your class library.

After, run Update-Database and it should apply the migration.

If you are still having issues. Make sure you are running the latest SDK. https://www.microsoft.com/net/download

More info can be found in the Docs. https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/