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.61k stars 3.14k forks source link

Nullable PK been mapped to NOT Null during code first migration generating #34216

Closed stevenxi closed 2 weeks ago

stevenxi commented 1 month ago

Include your code

[Table("ProfileData")]
public class ProfileData
{
    [Key, Column(Order = 1), DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int? PersonId { get; set; }

    [Key, Column(Order = 2), DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int? ProfileTypeId { get; set; }

    public string Value { get; set; }
}

Migration generated as following:

            migrationBuilder.CreateTable(
                name: "ProfileData",
                columns: table => new
                {
                    PersonId = table.Column<int>(type: "int", nullable: false),
                    ProfileTypeId = table.Column<int>(type: "int", nullable: false),
                    Value = table.Column<string>(type: "nvarchar(max)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_ProfileData", x => new { x.PersonId, x.ProfileTypeId });
                });

Migration script generated as following:

CREATE TABLE [ProfileData] (
    [PersonId] int NOT NULL,
    [ProfileTypeId] int NOT NULL,
    [Value] nvarchar(max) NOT NULL,
    CONSTRAINT [PK_ProfileData] PRIMARY KEY ([PersonId], [ProfileTypeId])
);

It should be either allows NULL PK, or throws exception when generating migrations. But not changed mapping quietly.

Include verbose output

Please include --verbose output when filing bugs about the dotnet ef or Package Manager Console tools.

Use triple-tick fences for tool output. For example:

C:\Program Files\dotnet\dotnet.exe exec --depsfile C:\code\NoSourceControl\ConsoleApp2\EFBugDemo\bin\Debug\net8.0\EFBugDemo.deps.json --additionalprobingpath C:\Users\StevenXi\.nuget\packages --additionalprobingpath "C:\Program Files\dotnet\sdk\NuGetFallbackFolder" --runtimeconfig C:\code\NoSourceControl\ConsoleApp2\EFBugDemo\bin\Debug\net8.0\EFBugDemo.runtimeconfig.json C:\Users\StevenXi\.nuget\packages\microsoft.entityframeworkcore.tools\8.0.7\tools\netcoreapp2.0\any\ef.dll migrations add Initial --json --verbose --no-color --prefix-output --assembly C:\code\NoSourceControl\ConsoleApp2\EFBugDemo\bin\Debug\net8.0\EFBugDemo.dll --project C:\code\NoSourceControl\ConsoleApp2\EFBugDemo\EFBugDemo.csproj --startup-assembly C:\code\NoSourceControl\ConsoleApp2\EFBugDemo\bin\Debug\net8.0\EFBugDemo.dll --startup-project C:\code\NoSourceControl\ConsoleApp2\EFBugDemo\EFBugDemo.csproj --project-dir C:\code\NoSourceControl\ConsoleApp2\EFBugDemo\ --language C# --configuration Debug --working-dir C:\code\NoSourceControl\ConsoleApp2 --root-namespace EFBugDemo --nullable
Using assembly 'EFBugDemo'.
Using startup assembly 'EFBugDemo'.
Using application base 'C:\code\NoSourceControl\ConsoleApp2\EFBugDemo\bin\Debug\net8.0'.
Using working directory 'C:\code\NoSourceControl\ConsoleApp2\EFBugDemo'.
Using root namespace 'EFBugDemo'.
Using project directory 'C:\code\NoSourceControl\ConsoleApp2\EFBugDemo\'.
Remaining arguments: .
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Found IDesignTimeDbContextFactory implementation 'DbContextFactory'.
Found DbContext 'DemoContext'.
Finding application service provider in assembly 'EFBugDemo'...
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...
Using DbContext factory 'DbContextFactory'.
Using context 'DemoContext'.
Finding design-time services referenced by assembly 'EFBugDemo'...
Finding design-time services referenced by assembly 'EFBugDemo'...
No referenced design-time services were found.
Finding design-time services for provider 'Microsoft.EntityFrameworkCore.SqlServer'...
Using design-time services from provider 'Microsoft.EntityFrameworkCore.SqlServer'.
Finding IDesignTimeServices implementations in assembly 'EFBugDemo'...
No design-time services were found.
Writing migration to 'C:\code\NoSourceControl\ConsoleApp2\EFBugDemo\Migrations\20240712123426_Initial.cs'.
Writing model snapshot to 'C:\code\NoSourceControl\ConsoleApp2\EFBugDemo\Migrations\DemoContextModelSnapshot.cs'.
'DemoContext' disposed.

Include provider and version information

EF Core version: 8.0.7 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: net8 Operating system: Windows 11 IDE: Visual Studio 2022 17.10.3

ajcvickers commented 1 month ago

@stevenxi EF model building always configures the PK property as required, even if the CLR type is nullable. Migrations creates a database schema that most closely matches this. If you want the PK to be nullable in the database, then you can edit that in the database, but since EF doesn't support null primary key values, it will make the database incompatible with EF if there are any nulls in that column.

stevenxi commented 1 month ago

@ajcvickers , I understand that, after all, not all database supports nullable PK, SQL Server is just an execption. So it's absolutely fine.

But user need to be notified during migration generation, otherwise there will be runtime error. Just like 'lazy loading property not being virtual' kind of exception, during either migration, or EF initialization.