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.66k stars 3.15k forks source link

Exception when applying database migrations containing spatial data #13267

Closed corstian closed 5 years ago

corstian commented 6 years ago

Applying Entity Framework Core migrations with the 2.2.0 previews (and spatial extensions) does not work.

Exception message:

Object reference not set to an instance of an object.

Stack trace:

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.EntityFrameworkCore.Migrations.MigrationsSqlGenerator.GetColumnType(String schema, String table, String name, Type clrType, Nullable`1 unicode, Nullable`1 maxLength, Nullable`1 fixedLength, Boolean rowVersion, IModel model)
   at Microsoft.EntityFrameworkCore.Migrations.MigrationsSqlGenerator.ColumnDefinition(String schema, String table, String name, Type clrType, String type, Nullable`1 unicode, Nullable`1 maxLength, Nullable`1 fixedLength, Boolean rowVersion, Boolean nullable, Object defaultValue, String defaultValueSql, String computedColumnSql, IAnnotatable annotatable, IModel model, MigrationCommandListBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGenerator.ColumnDefinition(String schema, String table, String name, Type clrType, String type, Nullable`1 unicode, Nullable`1 maxLength, Nullable`1 fixedLength, Boolean rowVersion, Boolean nullable, Object defaultValue, String defaultValueSql, String computedColumnSql, Boolean identity, IAnnotatable annotatable, IModel model, MigrationCommandListBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGenerator.ColumnDefinition(String schema, String table, String name, Type clrType, String type, Nullable`1 unicode, Nullable`1 maxLength, Nullable`1 fixedLength, Boolean rowVersion, Boolean nullable, Object defaultValue, String defaultValueSql, String computedColumnSql, IAnnotatable annotatable, IModel model, MigrationCommandListBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGenerator.ColumnDefinition(AddColumnOperation operation, IModel model, MigrationCommandListBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.MigrationsSqlGenerator.Generate(CreateTableOperation operation, IModel model, MigrationCommandListBuilder builder, Boolean terminate)
   at Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGenerator.Generate(CreateTableOperation operation, IModel model, MigrationCommandListBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.MigrationsSqlGenerator.Generate(MigrationOperation operation, IModel model, MigrationCommandListBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.MigrationsSqlGenerator.Generate(IReadOnlyList`1 operations, IModel model)
   at Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGenerator.Generate(IReadOnlyList`1 operations, IModel model)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.GenerateUpSql(Migration migration)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

Edit:

After trying to update the database with verbose mode enabled we can see a bit better what's going on:

Using project 'C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\ConsoleApp3.csproj'.
Using startup project 'C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\ConsoleApp3.csproj'.
Writing 'C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\obj\ConsoleApp3.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\corstian\AppData\Local\Temp\tmpE575.tmp /verbosity:quiet /nologo C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\ConsoleApp3.csproj
Writing 'C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\obj\ConsoleApp3.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\corstian\AppData\Local\Temp\tmpEBCF.tmp /verbosity:quiet /nologo C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\ConsoleApp3.csproj
dotnet build C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\ConsoleApp3.csproj /verbosity:quiet /nologo

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:02.00
dotnet exec --depsfile C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\netcoreapp2.1\ConsoleApp3.deps.json --additionalprobingpath C:\Users\corstian\.nuget\packages --additionalprobingpath "C:\Program Files\dotnet\sdk\NuGetFallbackFolder" --runtimeconfig C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\netcoreapp2.1\ConsoleApp3.runtimeconfig.json "C:\Program Files\dotnet\sdk\2.2.100-preview1-009349\DotnetTools\dotnet-ef\2.2.0-preview1-35029\tools\netcoreapp2.2\any\tools\netcoreapp2.0\any\ef.dll" database update --assembly C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\netcoreapp2.1\ConsoleApp3.dll --startup-assembly C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\netcoreapp2.1\ConsoleApp3.dll --project-dir C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\ --language C# --working-dir C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3 --verbose --root-namespace ConsoleApp3
Using assembly 'ConsoleApp3'.
Using startup assembly 'ConsoleApp3'.
Using application base 'C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\netcoreapp2.1'.
Using working directory 'C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3'.
Using root namespace 'ConsoleApp3'.
Using project directory 'C:\Users\corstian\source\repos\ConsoleApp3\ConsoleApp3\'.
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider...
Finding IWebHost accessor...
No CreateWebHostBuilder(string[]) method was found on type 'ConsoleApp3.Program'.
No application service provider was found.
Finding DbContext classes in the project...
Found DbContext 'BugDbContext'.
Using context 'BugDbContext'.
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 'ConsoleApp3'.
No referenced design-time services were found.
Finding IDesignTimeServices implementations in assembly 'ConsoleApp3'...
No design-time services were found.
Migrating using database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Opening connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Opened connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Closing connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Closed connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Opening connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Opened connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Executed DbCommand (194ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Closing connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Closed connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Opening connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Opened connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Closing connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Closed connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Opening connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Opened connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Executed DbCommand (107ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Closing connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Closed connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Opening connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Opened connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [MigrationId], [ProductVersion]
FROM [__EFMigrationsHistory]
ORDER BY [MigrationId];
Executed DbCommand (26ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [MigrationId], [ProductVersion]
FROM [__EFMigrationsHistory]
ORDER BY [MigrationId];
A data reader was disposed.
Closing connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Closed connection to database 'EFCoreSpatialBugRepro' on server '(localdb)\.'.
Applying migration '20180910172233_0.1'.
'BugDbContext' disposed.
System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.EntityFrameworkCore.Migrations.MigrationsSqlGenerator.GetColumnType(String schema, String table, String name, Type clrType, Nullable`1 unicode, Nullable`1 maxLength, Nullable`1 fixedLength, Boolean rowVersion, IModel model)
   at Microsoft.EntityFrameworkCore.Migrations.MigrationsSqlGenerator.ColumnDefinition(String schema, String table, String name, Type clrType, String type, Nullable`1 unicode, Nullable`1 maxLength, Nullable`1 fixedLength, Boolean rowVersion, Boolean nullable, Object defaultValue, String defaultValueSql, String computedColumnSql, IAnnotatable annotatable, IModel model, MigrationCommandListBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGenerator.ColumnDefinition(String schema, String table, String name, Type clrType, String type, Nullable`1 unicode, Nullable`1 maxLength, Nullable`1 fixedLength, Boolean rowVersion, Boolean nullable, Object defaultValue, String defaultValueSql, String computedColumnSql, Boolean identity, IAnnotatable annotatable, IModel model, MigrationCommandListBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGenerator.ColumnDefinition(String schema, String table, String name, Type clrType, String type, Nullable`1 unicode, Nullable`1 maxLength, Nullable`1 fixedLength, Boolean rowVersion, Boolean nullable, Object defaultValue, String defaultValueSql, String computedColumnSql, IAnnotatable annotatable, IModel model, MigrationCommandListBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGenerator.ColumnDefinition(AddColumnOperation operation, IModel model, MigrationCommandListBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.MigrationsSqlGenerator.Generate(CreateTableOperation operation, IModel model, MigrationCommandListBuilder builder, Boolean terminate)
   at Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGenerator.Generate(CreateTableOperation operation, IModel model, MigrationCommandListBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.MigrationsSqlGenerator.Generate(MigrationOperation operation, IModel model, MigrationCommandListBuilder builder)
   at Microsoft.EntityFrameworkCore.Migrations.MigrationsSqlGenerator.Generate(IReadOnlyList`1 operations, IModel model)
   at Microsoft.EntityFrameworkCore.Migrations.SqlServerMigrationsSqlGenerator.Generate(IReadOnlyList`1 operations, IModel model)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.GenerateUpSql(Migration migration)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Object reference not set to an instance of an object.

Steps to reproduce

Please note that I have been using the 2.2.0-preview2-35148 packages as there have been problems resolving the System.Data.SqlClient dependency on later versions.

For a minimalistic demo project showing the set up for reproducing this bug; see: https://github.com/corstian/efcore-migrations-spatial-bug-reproduction.

Migrations have been generated. Running dotnet ef database update should trigger said bug.

Further technical details

EF Core version: 2.2.0-preview-26820-02 Database Provider: Microsoft.EntityFrameworkCore.SqlServer Operating system: Windows 10 Pro Version: 10.0.17134 Build 17134

corstian commented 6 years ago

Involves testing the progress booked on #1100. FYI

bricelam commented 6 years ago

We should still look in to the exception, but does it work if you add a class like this to your project?

class MyDesignTimeServices : IDesignTimeServices
{
    public void ConfigureDesignTimeServices(IServiceCollection services)
        => services.AddEntityFrameworkSqlServerNetTopologySuite();
}
corstian commented 6 years ago

Adding the design time services does not change the end result. I can verify that the service has been found in the log, but the same exception still occurs.

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 'EFCoreSpatialBugRepro'.
No referenced design-time services were found.
Finding IDesignTimeServices implementations in assembly 'EFCoreSpatialBugRepro'...
Using design-time services from class 'MyDesignTimeServices'.
jwdb commented 6 years ago

The modelbuilder for entities with spatial data, which is generated with the migrations, contain the following configuration:

b.Property<SqlBytes>("Location");

Changing this into the following (or whatever specific spatial type you're using) in all your auto-generated migration files:

b.Property<Point>("Location");

Will make it work correctly!

corstian commented 6 years ago

Thanks JW!

Note that, even with the MyDesignTimeServices, the migrations will contain the SqlBytes type for spatial data fields.

bricelam commented 6 years ago

Yep, that's a bug. Manually changing it back to Point should fix the issue.

bricelam commented 6 years ago

Wow, for some reason I thought you were trying to dbcontext scaffold, not database update. The design-time services are unnecessary.

bricelam commented 5 years ago

Fixed by PR #13380

ffMathy commented 5 years ago

I'm having this even on the latest preview 3 packages.

ffMathy commented 5 years ago

However, I should add that it now doesn't happen for dotnet ef migrations add, but dotnet ef database update instead.

bricelam commented 5 years ago

Did you delete your existing migrations and re-generate them?

ffMathy commented 5 years ago

Nope. Why is that needed?

bricelam commented 5 years ago

Migrations generated by a preview of EF Core aren't guaranteed to work with future versions. (The fix for this issue was to generate different code.)

ffMathy commented 5 years ago

But I came from a production state of RTM, installed preview 3 for the first time, added a Point property on my model class, and generated the migration.

In other words, the error could be happening for countless users when this package goes RTM.

smitpatel commented 5 years ago

installed preview 3 for the first time, added a Point property on my model class, and generated the migration.

That is exactly something not supported fully. You can create migration after installing preview package and try it out but once RTM is released, you should install RTM package and recreate migrations which were generated using preview package.

bricelam commented 5 years ago

@ffMathy Could you file a new issue detailing the steps so we can investigate? This was supposed to be fixed in 2.2.0-preview3, but it looks like you're still hitting it (or something like it).

ffMathy commented 5 years ago

@smitpatel that is not what I am saying.

I had no preview, I came from RTM, and for the first time ever installed preview 3, added a Point, and ran a migration. Then this error came up.

That should not happen either way, because then it will happen to RTM too.

ffMathy commented 5 years ago

Well @bricelam wiping all my existing migrations helped, but once again, these were RTM migrations, so it'll be nasty for the users when this comes out and they use it.

I can't provide steps to reproduce, as the code is under NDA.

nammadhu commented 2 years ago

Remove everything else just keep below code. Especially DesignTimeBMDbContext : IDesignTimeDbContextFactory this makes poblem. Just remove it. Am using 2022 and dotnet 6 public class MyDesignTimeServices : IDesignTimeServices { public void ConfigureDesignTimeServices(IServiceCollection services) => services.AddEntityFrameworkSqlServerNetTopologySuite(); }