Add migration with different assembly

有些话、适合烂在心里 提交于 2019-11-28 18:40:35

All EF commands have this check:

if (targetAssembly != migrationsAssembly) 
       throw MigrationsAssemblyMismatchError;

targetAssembly = the target project you are operating on. On the command line, it is the project in the current working directory. In Package Manager Console, it is whatever project is selected in the drop down box on the top right of that window pane.

migrationsAssembly = assembly containing code for migrations. This is configurable. By default, this will be the assembly containing the DbContext, in your case, Project.Data.dll. As the error message suggests, you have have a two options to resolve this

1 - Change target assembly.

cd Project.Data/
dotnet ef --startup-project ../Project.Api/ migrations add Initial

// code doesn't use .MigrationsAssembly...just rely on the default
options.UseSqlServer(connection)

2 - Change the migrations assembly.

cd Project.Api/
dotnet ef migrations add Initial

// change the default migrations assembly
options.UseSqlServer(connection, b => b.MigrationsAssembly("Project.Api"))
Dre Ross

I had the same problem until I noticed that on the package manager console top bar => "Default Projects" was supposed to be "Project.Data" and not "Project.API".

Once you target the "Project.Data" from the dropdown list and run the migration you should be fine.

Using EF Core 2, you can easily separate your Web project from your Data (DbContext) project. In fact, you just need to implement the IDesignTimeDbContextFactory interface. According to Microsoft docs, IDesignTimeDbContextFactory is:

A factory for creating derived DbContext instances. Implement this interface to enable design-time services for context types that do not have a public default constructor. At design-time, derived DbContext instances can be created in order to enable specific design-time experiences such as Migrations. Design-time services will automatically discover implementations of this interface that are in the startup assembly or the same assembly as the derived context.

In the bottom code snippet you can see my implementation of DbContextFactory which is defined inside my Data project:

public class DbContextFactory : IDesignTimeDbContextFactory<KuchidDbContext>
{
    public KuchidDbContext CreateDbContext(string[] args)
    {
        var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .Build();

        var dbContextBuilder = new DbContextOptionsBuilder<KuchidDbContext>();

        var connectionString = configuration.GetConnectionString("Kuchid");

        dbContextBuilder.UseSqlServer(connectionString);

        return new KuchidDbContext(dbContextBuilder.Options);
    }
}

Now, I can initialize EF migration by setting my Web project as the StartUp project and selecting my Data project inside the Package Manager Console.

Add-Migration initial

You can find more details here. However, this blog post uses an obsoleted class instead of IDesignTimeDbContextFactory.

I ran on the same problem and found this

We’re you trying to run your migrations on a class library? So was I. Turns out this isn’t supported yet, so we’ll need to work around it.

EDIT: I found solution on this git repo

Currently I think EF only supports to add migrations on projects not yet on class libraries.

And just side note for anybody else who wants to add migrations to specific folder inside your project:

EF CLI not support this yet. I tried --data-dir but it didn't work.

The only thing works is to use Package Manager Console:

  1. Pick your default project
  2. use -OutputDir command parameter, .e.g., Add-Migration InitConfigurationStore -OutputDir PersistedStores/ConfigurationStore command will output the mgiration to the folder 'PersistedStores/ConfigurationStore' in my project.

Updates as of 10/12/2017

public void ConfigureServices(IServiceCollection services)
{
    ...

    string dbConnectionString = services.GetConnectionString("YOUR_PROJECT_CONNECTION");
    string assemblyName = typeof(ProjectDbContext).Namespace;

    services.AddDbContext<ProjectDbContext>(options =>
        options.UseSqlServer(dbConnectionString,
            optionsBuilder =>
                optionsBuilder.MigrationsAssembly(assemblyName)
        )
   );

   ...
}

(ASP.NET Core 2+)

Had the same issue. Here is what I did:

  1. Reference the project that contains the DbContext (Project.A) from the project that will contain the migrations (Project.B).

  2. Move the existing migrations from Project.A to Project.B (If you don't have migrations - create them first)

  3. Configure the migrations assembly inside Project.A

options.UseSqlServer( connectionString, x => x.MigrationsAssembly("Project.A"));

Assuming your projects reside in the same parent folder:

  1. dotnet ef migrations add Init --project ../AskGoo.Data -c DbContext

The migrations now go to Project.B

Source: Microsoft

Add-Migration NewMigration -Project MyApp.Migrations

I was facing similar issue, though answers seems straight forward somehow they didn't work. My Answer is similar to @Ehsan Mirsaeedi, with small change in DbContextFactory class. Instead of Adding migration assembly name in Startup class of API, I have mentioned in DbContextFactory class which is part of Data project(class library).

public class DbContextFactory : IDesignTimeDbContextFactory<KuchidDbContext>
{
   public KuchidDbContext CreateDbContext(string[] args)
   {
       var configuration = new ConfigurationBuilder()
          .SetBasePath(Directory.GetCurrentDirectory())
          .AddJsonFile("appsettings.json")
          .Build();

       var dbContextBuilder = new DbContextOptionsBuilder<KuchidDbContext>();

       var connectionString = configuration.GetConnectionString("connectionString");

       var migrationAssemblyName= configuration.GetConnectionString("migrationAssemblyName");

       dbContextBuilder.UseSqlServer(connectionString, o => o.MigrationAssembly(migrationAssemblyName));

       return new KuchidDbContext(dbContextBuilder.Options);
   }
}

You would need 'Microsoft.Extensions.Configuration' and 'Microsoft.Extensions.Configuration.Json' for SetBasePath & AddJsonFile extensions to work.

Note: I feel this is just a work around. It should pickup the DbContextOptions from the startup class somehow it is not. I guess there is definitely some wiring issue.

For all of you who have multiple startup projects.

Notice that you need to set your target project as startup project - Project.Api(form the question example) should be the startup project.

Hope that will help someone :)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!