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.75k stars 3.18k forks source link

`Sqlite:Autoincrement` is not generated for key column when the entity has owned property #34608

Open noelex opened 1 month ago

noelex commented 1 month ago

Consider the following configuration:

public class SomeRandomEntity
{
    public long Id { get; set; }

    public OwnedEntity? Owned { get; set; }
}

public class OwnedEntity
{
    public int OwnedField { get; set; }
}

internal class ReproDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite();
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<SomeRandomEntity>(entity =>
        {
            entity.HasKey(x => x.Id);
            entity.OwnsOne(x => x.Owned);
        });
    }
}

dotnet ef migrations add generates a migration with the following code:

migrationBuilder.CreateTable(
    name: "SomeRandomEntity",
    columns: table => new
    {
        Id = table.Column<long>(type: "INTEGER", nullable: false),
        Owned_OwnedField = table.Column<int>(type: "INTEGER", nullable: true)
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_SomeRandomEntity", x => x.Id);
    });

Note that Sqlite:Autoincrement is missing on Id. This can be 'fixed' by either changing the name of the entity to MyEntity:

migrationBuilder.CreateTable(
    name: "MyEntity",
    columns: table => new
    {
        Id = table.Column<long>(type: "INTEGER", nullable: false)
            .Annotation("Sqlite:Autoincrement", true),
        Owned_OwnedField = table.Column<int>(type: "INTEGER", nullable: true)
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_MyEntity", x => x.Id);
    });

or by removing Owned property:

migrationBuilder.CreateTable(
    name: "SomeRandomEntity",
    columns: table => new
    {
        Id = table.Column<long>(type: "INTEGER", nullable: false)
            .Annotation("Sqlite:Autoincrement", true)
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_SomeRandomEntity", x => x.Id);
    });

Reverting Microsoft.EntityFrameworkCore.Sqlite and Microsoft.EntityFrameworkCore.Design to 6.0.33 also fixes the issue.

EF Core version: 8.0.8 Database provider: Microsoft.EntityFrameworkCore.Sqlite Target framework: net-8.0

cincuranet commented 1 month ago

Note: Works correctly with Microsoft.EntityFrameworkCore.SqlServer. So probably SQLite provider specific.

noelex commented 1 month ago

https://github.com/dotnet/efcore/blob/90d079985f33ae91c05b98ecf65e0ce38270ba55/src/EFCore.Sqlite.Core/Metadata/Internal/SqliteAnnotationProvider.cs#L68 This line might be problematic since PropertyMappings may contain a shadow ColumnMapping for the owned entity:

ColumnMapping: OwnedEntity.SomeRandomEntityId - SomeRandomEntity.Id
ColumnMapping: SomeRandomEntity.Id - SomeRandomEntity.Id

Things will only work when the first ColumnMapping happens to be the right one.

And these may also cause problems? https://github.com/dotnet/efcore/blob/90d079985f33ae91c05b98ecf65e0ce38270ba55/src/EFCore.Relational/Metadata/IColumn.cs#L26-L72