dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.79k stars 3.19k forks source link

xModelSnapshot.cs not respecting '--output-dir' parameter for 'dotnet ef'? #24339

Open edespong opened 3 years ago

edespong commented 3 years ago

Related but not the same issue? #10036

The documentation at Entity Framework Core tools reference states: --output-dir <PATH> - The directory use to output the files. [...]

However when running: dotnet ef migrations add InitialCreate --project src\Infrastructure --startup-project src\DatabaseMigration --output-dir ..\DatabaseMigration\Migrations --verbose

Only the migrations files are put in the output directory. My DbContext is called Database, and the file called DatabaseModelSnapshot.cs is put under src\Infrastructure\Migrations\DatabaseModelSnapshot.cs.

Is this a bug in the dotnet ef code, or an error in the documentation?

Verbose output:

dotnet exec --depsfile xxx\src\DatabaseMigration\bin\Debug\net5.0\Application1.DatabaseMigration.deps.json --additionalprobingpath C:\Users\my-user\.nuget\packages --additionalprobingpath "C:\Program Files\dotnet\sdk\NuGetFallbackFolder" --runtimeconfig xxx\src\DatabaseMigration\bin\Debug\net5.0\Application1.DatabaseMigration.runtimeconfig.json C:\Users\my-user\.dotnet\tools\.store\dotnet-ef\5.0.3\dotnet-ef\5.0.3\tools\netcoreapp3.1\any\tools\netcoreapp2.0\any\ef.dll migrations 
add InitialCreate --output-dir ..\DatabaseMigration\Migrations --assembly xxx\src\DatabaseMigration\bin\Debug\net5.0\Application1.Infrastructure.dll --startup-assembly xxx\src\DatabaseMigration\bin\Debug\net5.0\Application1.DatabaseMigration.dll --project-dir xxx\src\Infrastructure\ --language C# --working-dir xxx --verbose --root-namespace Application1.Infrastructure
Using assembly 'Application1.Infrastructure'.
Using startup assembly 'Application1.DatabaseMigration'.
Using application base 'xxx\src\DatabaseMigration\bin\Debug\net5.0'.
Using working directory 'xxx\src\DatabaseMigration'.
Using root namespace 'Application1.Infrastructure'.
Using project directory 'xxx\src\Infrastructure\'.
Remaining arguments: .
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider in assembly 'Application1.DatabaseMigration'...
Finding Microsoft.Extensions.Hosting service provider...
No static method 'CreateHostBuilder(string[])' was found on class 'Program'.
No application service provider was found.
Finding DbContext classes in the project...
Found DbContext 'Database'.
Using context 'Database'.
Database is not configured. Configuring from environment..
Finding design-time services for provider 'Microsoft.EntityFrameworkCore.SqlServer'...
Using design-time services from provider 'Microsoft.EntityFrameworkCore.SqlServer'.
Finding design-time services referenced by assembly 'Application1.DatabaseMigration'...
Finding design-time services referenced by assembly 'Application1.Infrastructure'...
No referenced design-time services were found.
Finding IDesignTimeServices implementations in assembly 'Application1.DatabaseMigration'...
No design-time services were found.
DetectChanges starting for 'Database'.
DetectChanges completed for 'Database'.
Writing migration to 'xxx\src\DatabaseMigration\Migrations\20210308082724_InitialCreate.cs'.
Writing model snapshot to 'xxx\src\Infrastructure\Migrations\DatabaseModelSnapshot.cs'.
'Database' disposed.

Version info

dotnet --version: 5.0.102 dotnet ef --version: Entity Framework Core .NET Command-line Tools 5.0.3

edespong commented 3 years ago

On further trial and error, if I add --namespace Foo.Bar.Baz as a paramter, e.g.

dotnet ef migrations add InitialCreate --project src\Infrastructure --namespace Foo.Bar.Baz --startup-project src\DatabaseMigration --output-dir ..\DatabaseMigration\Migrations

Then the DatabaseModelSnapshot.cs will be put into src\Infrastructure\Foo\Bar\Baz\DatabaseModelSnapshot.cs . This also seems like it is broken, because I would not be able to set a namespace without altering the location of the output file.

bricelam commented 3 years ago

We try to preserve the existing location of the model snapshot; it only honors --output-dir on the first migration. (see #22217)

Your second comments looks like a bug. We've had several surrounding the namespace options and how they interact with the directory options.

edespong commented 3 years ago

We try to preserve the existing location of the model snapshot; it only honors --output-dir on the first migration. (see #22217)

The migration I am trying is the first migration.

I am attaching a minimal solution for reproduction. Note that you probably need to change the connection string in src\DatabaseMigration\appsettings.json to run it properly. 24339-reproduction.zip

jeancallisti commented 3 years ago

+1 to everything @edespong said.

I should add that this issue goes both ways, i.e. problems also arise when doing "migrations remove" : If the migrations are in a custom directory (in a different project from the DbContext) then EF seems to overlook (can't find?) some of the existing classes it generated before and it deletes the Snapshot altogether -- even when the "remove" didn't operate on the Initial migration but on a subsequent migration.

As it is, it's not possible to work cleanly as described here : https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/projects?tabs=dotnet-core-cli

JasonFoglia commented 3 years ago

Here is a work around for this issue that worked for me. MigrationsAssembly

I have 4 projects in one solution. Data layer and Web layer. All EF migrations go into the Data Layer now inside of being split between the 2 projects.

This is in the Data layer:

services.AddDbContext<EFContext>( options => options.UseSqlServer(connectionStrings.DefaultConnection, x => x.MigrationsAssembly(typeof(EFContext).Assembly.FullName)));

twilek commented 2 years ago

I have this problem as well. I have a project with 12 different DbContexts in as many different projects, but want all the migrations on one place. This has worked without problems before, but after updating to the latest version of ef the snapshots are placed in the project dir instead of in my output path. And it happens on the initial migration as well.

ajcvickers commented 10 months ago

Note from design meeting: if you specify output-path, then we will respect it. See also #32738.

StefH commented 8 months ago

Just to confirm: this is still not working as intended?

ajcvickers commented 8 months ago

@StefH This issue is in the Backlog milestone. This means that it is not planned for the next release. We will re-assess the backlog following the this release and consider this item at that time. However, keep in mind that there are many other high priority features with which it will be competing for resources. Make sure to vote (👍) for this issue if it is important to you.

Lu1815 commented 7 months ago

I still have the same issue with the current version of EF Core Tools!

atrauzzi commented 5 days ago

Just a note, but I just initialized fresh migrations and it's definitely not respecting the --output-dir for the snapshot.

I have my <RootNamespace> in the project set to ProjectName.Domain.Migrations, so I expect everything adjacent to the .csproj file to be considered in that namespace.

What ends up happening though is efcore migrations ends up putting the snapshot in a dir called Migrations/.