Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a warning when store-generated PK is not supported #11162

Closed
Tracked by #22946
viveknuna opened this issue Mar 6, 2018 · 15 comments · Fixed by #28534
Closed
Tracked by #22946

Add a warning when store-generated PK is not supported #11162

viveknuna opened this issue Mar 6, 2018 · 15 comments · Fixed by #28534
Labels
area-model-building closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Milestone

Comments

@viveknuna
Copy link

viveknuna commented Mar 6, 2018

I'm using ABP framework which is built on top of asp.net core and using entity framework core. I have tried to create PK to a different column other than the default Id column with the help of this solution. Its working fine for every scenario, but my test cases are failing. I have created TestId as PK, Id as autoincrement identity.

It's failing when I'm running test case to create the record and giving the following exception.

SQLite Error 19: 'NOT NULL constraint failed: Test.Id'.

Testcase:

public async Task Should_Create_Test_With_Valid_Arguments()
{
    var Test = await CreateNewTest(K_TESTCode1);
    Test.Code = await _TestAppService.CreateTest(Test);

    UsingDbContext((System.Action<EntityFrameworkCore.MyProjectDbContext>)(context =>
    {
        context.Test.FirstOrDefault(
            u => u.Code == Test.Code
        ).ShouldNotBeNull();
    }));
}

CreateNewTest Method

public async Task<TestDetailsDto> CreateNewTest(string Code)
{
    return CreateTestEntity(Code);
}

public TestDetailsDto CreateTestEntity(string Code)
{
    var Test = new TestDetailsDto
    {
        Code = Code,
    };
    return Test;
}

CreateTest Method

public async Task<string> CreateTest(TestDetailsDto input)
{
    try
    {
        int TestId = await InsertAndGetIdAsync(ObjectMapper.Map<Test>(input));
        return input.Code;
    }
    catch (Exception ex)
    {
        throw new UserFriendlyException(ex.Message);
    }
}

StackTrace

Starting: MyCompany.MyProject.Tests
[3/6/2018 5:49:05 AM Error] [xUnit.net 00:00:26.6288060] MyCompany.MyProject.Tests.Classifications.TestAppService_Test.Should_Create_Classification_With_Valid_Arguments [FAIL]
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6308959] Microsoft.EntityFrameworkCore.DbUpdateException : An error occurred while updating the entries. See the inner exception for details.
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6309648] ---- Microsoft.Data.Sqlite.SqliteException : SQLite Error 19: 'NOT NULL constraint failed: Test.Id'.
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6323228] Stack Trace:
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6335736] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.d__32.MoveNext()
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6336454] --- End of stack trace from previous location where exception was thrown ---
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6336945] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6337390] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6337813] at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.d__10.MoveNext()
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6338186] --- End of stack trace from previous location where exception was thrown ---
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6338566] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6338982] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6339344] at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6339755] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<SaveChangesAsync>d__61.MoveNext() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6340070] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6340441] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6340850] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6341236] at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6341641] at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.d__59.MoveNext()
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6341947] --- End of stack trace from previous location where exception was thrown ---
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6342311] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6342694] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6343065] at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6343431] at Microsoft.EntityFrameworkCore.DbContext.<SaveChangesAsync>d__48.MoveNext() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6343752] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6344115] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6344511] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6345061] D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\AbpDbContext.cs(215,0): at Abp.EntityFrameworkCore.AbpDbContext.<SaveChangesAsync>d__49.MoveNext() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6348796] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6349402] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6349858] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6350373] D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\Uow\EfCoreUnitOfWork.cs(163,0): at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.<SaveChangesInDbContextAsync>d__20.MoveNext() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6350804] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6351201] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6351665] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6352134] D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\Uow\EfCoreUnitOfWork.cs(68,0): at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.<SaveChangesAsync>d__12.MoveNext() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6352535] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6352935] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6353330] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6353808] D:\Github\aspnetboilerplate\src\Abp.EntityFrameworkCore\EntityFrameworkCore\Uow\EfCoreUnitOfWork.cs(83,0): at Abp.EntityFrameworkCore.Uow.EfCoreUnitOfWork.<CompleteUowAsync>d__14.MoveNext() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6354207] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6354685] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6355115] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6355558] D:\Github\aspnetboilerplate\src\Abp\Domain\Uow\UnitOfWorkBase.cs(276,0): at Abp.Domain.Uow.UnitOfWorkBase.<CompleteAsync>d__57.MoveNext() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6355921] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6356306] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6356695] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6357135] D:\Github\aspnetboilerplate\src\Abp\Domain\Uow\UnitOfWorkInterceptor.cs(90,0): at Abp.Domain.Uow.UnitOfWorkInterceptor.<>c__DisplayClass6_0.<<PerformAsyncUow>b__0>d.MoveNext() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6357587] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6359838] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6360322] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6360807] D:\Github\aspnetboilerplate\src\Abp\Threading\InternalAsyncHelper.cs(40,0): at Abp.Threading.InternalAsyncHelper.<AwaitTaskWithPostActionAndFinally>d__1.MoveNext() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6361199] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6361583] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6362001] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6362425] D:\Github\aspnetboilerplate\src\Abp\Threading\InternalAsyncHelper.cs(20,0): at Abp.Threading.InternalAsyncHelper.<AwaitTaskWithFinally>d__0.MoveNext() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6362869] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6363327] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6363782] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6364332] C:\Users\pooja.dhadse\Source\MyProject\aspnet-core\test\MyCompany.MyProject.Tests\Classifications\TestAppService_Test.cs(20,0): at MyCompany.MyProject.Tests.Classifications.TestAppService_Test.<Should_Create_Classification_With_Valid_Arguments>d__1.MoveNext() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6364752] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6365185] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6365609] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6365946] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6366305] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6366710] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6367020] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6367403] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6367790] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6368122] ----- Inner Stack Trace ----- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6368492] at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6368883] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6369347] at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6369741] at Microsoft.Data.Sqlite.SqliteCommand.<ExecuteDbDataReaderAsync>d__52.MoveNext() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6370066] --- End of stack trace from previous location where exception was thrown --- [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6370420] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6370829] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6371183] at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6371579] at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.d__17.MoveNext()
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6371886] --- End of stack trace from previous location where exception was thrown ---
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6372250] at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6372632] at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6372995] at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6373387] at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.d__32.MoveNext()
[3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6922065] Finished: MyCompany.MyProject.Tests
[3/6/2018 5:49:06 AM Informational] ========== Run test finished: 1 run (0:00:28.3709989) ==========

Code:

public class Test: FullAuditedEntity
{
    // PK
    [MaxLength(NVarcharLength14), DataType(DataType.Text)]
    public virtual string Code { get; set; }

    // Unique constraint
    public int MyUniqueId { get; set; }
}

public class AbpProjectNameDbContext : AbpZeroDbContext<Tenant, Role, User, AbpProjectNameDbContext>
{
    /* Define a DbSet for each entity of the application */    
    public DbSet<Test> Tests { get; set; }

    public AbpProjectNameDbContext(DbContextOptions<AbpProjectNameDbContext> options) : base(options) {}

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Test>().Property(t => t.Id).ValueGeneratedOnAdd(); // Auto-increment
        modelBuilder.Entity<Test>().HasAlternateKey(t => t.Id);                // Auto-increment, closed-wont-fix: https://github.com/aspnet/EntityFrameworkCore/issues/7380
        modelBuilder.Entity<Test>().HasKey(t => t.Code);                       // PK
        modelBuilder.Entity<Test>().HasIndex(t => t.MyUniqueId).IsUnique();    // Unique constraint
    }
}

Generated migration:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.CreateTable(
        name: "Tests",
        columns: table => new
        {
            Code = table.Column<string>(nullable: false),
            Id = table.Column<int>(nullable: false)
                .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
            MyUniqueId = table.Column<int>(nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_Tests", x => x.Code);
        });

    migrationBuilder.CreateIndex(
        name: "IX_Tests_MyUniqueId",
        table: "Tests",
        column: "MyUniqueId",
        unique: true);
}

Usage:

public async Task MyMethod()
{
    await _repository.InsertAndGetIdAsync(new Test
    {
        Code = "One",
        MyUniqueId = 1
    });

    // Valid
    await _repository.InsertAndGetIdAsync(new Test
    {
        Code = "Two",
        MyUniqueId = 2
    });

    try
    {
        await _repository.InsertAndGetIdAsync(new Test
        {
            Code = "One", // PK conflict
            MyUniqueId = 3
        });
    }
    catch (Exception e)
    {
    }

    try
    {
        await _repository.InsertAndGetIdAsync(new Test
        {
            Code = "Three",
            MyUniqueId = 1 // Unique constraint conflict
        });
    }
    catch (Exception e)
    {
        throw;
    }

    return null;
}

Further technical details

EF Core version: 2.0.1
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10
IDE: Visual Studio 2017 15.4

@ajcvickers
Copy link
Member

@viveknuna Looks like the migration was generated against SQL Server, but is being used with SQLite. Does it work correctly if the migration is instead created for use with SQLite?

@viveknuna
Copy link
Author

Yes, migration is generated against sql server. I don’t run any migrations explicitly for my test cases, But test cases use SQLite. SQLite generates same schema.

So is this SQLite related issue or there is some problem with my current implementation?

Please let me know what should I try at my end?

@viveknuna
Copy link
Author

My application uses sql server only, but test cases use SQLite. I’m using XUnit.

@ajcvickers
Copy link
Member

@viveknuna Migrations are generated against the provider that you are using and may contain code specific to that provider. If you want to test against a different provider, then consider either:

  • Using EnsureDeleted/EnsureCreated for your tests so that they don't depend on the migrations at all
  • Use migrations against two providers using one of the approaches described in the docs

@ajcvickers ajcvickers added the closed-no-further-action The issue is closed and no further action is planned. label Mar 6, 2018
@voroninp
Copy link

@ajcvickers EnsureDeleted+EnsureCreatd is not working for me.

Entity Framework Core .NET Command-line Tools 2.2.4-servicing-10062
EF Core 2.2.4

Microsoft.EntityFrameworkCore.Database.Command:Error: Failed executing DbCommand (14ms)

[Parameters=[@p0='1' (DbType = String), @p1='1' (DbType = String), @p2='2019-06-20T15:08:52.8230073+00:00' (DbType = String)], CommandType='Text', CommandTimeout='30']
INSERT INTO "DevicesOrderStatus" ("OrderId", "Status", "UtcSetAt")
VALUES (@p0, @p1, @p2);
SELECT "Id"
FROM "DevicesOrderStatus"
WHERE changes() = 1 AND "OrderId" = @p0 AND "Id" = last_insert_rowid();

So I assume Id should have AUTOINCREMENT for SQLite because it is configured as b.Property<int>("Id").ValueGeneratedOnAdd() .

However, SQLite shows this SQL for the table:

CREATE TABLE "DevicesOrderStatus" (
    "OrderId" INTEGER NOT NULL,
    "Id" INTEGER NOT NULL,
    "Status" INTEGER NOT NULL,
    "UtcSetAt" TEXT NOT NULL,
    CONSTRAINT "PK_DevicesOrderStatus" PRIMARY KEY ("OrderId", "Id"),
    CONSTRAINT "FK_DevicesOrderStatus_DevicesOrder_OrderId" FOREIGN KEY ("OrderId") REFERENCES "DevicesOrder" ("Id") ON DELETE CASCADE,
    CONSTRAINT "FK_DevicesOrderStatus_DevicesOrderStatusType_Status" FOREIGN KEY ("Status") REFERENCES "DevicesOrderStatusType" ("Id") ON DELETE RESTRICT
)

I see nothing which indicates automatic increment of Id column.

DevicesOrderStatus is configured as an owned entity of an order:

internal sealed class DevicesOrderConfiguration : IEntityTypeConfiguration<DevicesOrder>
{
    public void Configure(EntityTypeBuilder<DevicesOrder> builder)
    {
        builder.ToTable("DevicesOrder");

        builder.Property(_ => _.Version)
            .HasDefaultValue(0)
            .IsConcurrencyToken();

        builder.Ignore(_ => _.OrderItemsCount);
        builder.Ignore(_ => _.CurrentStatus);

        builder.HasKey(_ => _.Id);

        builder.OwnsMany(_ => _.OrderItems, b =>
        {
            b.ToTable("DevicesOrderItem");

            b.HasForeignKey("OrderId");
            b.HasKey("OrderId", nameof(DevicesOrderItem.ModelId));

            b.HasOne<DeviceModel>()
                .WithMany()
                .HasForeignKey(m => m.ModelId)
                .IsRequired()
                .OnDelete(DeleteBehavior.Restrict);
        });

        builder.OwnsMany(_ => _.StatusHistory, b =>
        {
            b.ToTable("DevicesOrderStatus");

            b.HasForeignKey("OrderId");
            b.Property<int>("Id").ValueGeneratedOnAdd();
            b.HasKey("OrderId", "Id");

            b.HasOne<DevicesOrderStatusLookup>()
                .WithMany()
                .HasForeignKey(m => m.Status)
                .IsRequired()
                .OnDelete(DeleteBehavior.Restrict);
        });

        builder.HasOne<Organization>()
            .WithMany()
            .HasForeignKey(_ => _.OrganizationId)
            .IsRequired()
            .OnDelete(DeleteBehavior.Cascade);
    }
}

@ajcvickers
Copy link
Member

@voroninp See #15497. SQLite doesn't support auto-increment on composite keys.

@voroninp
Copy link

@ajcvickers I am spoiled by SQL Server =)

But is it hard for EF Core to detect this situation? Can EF signal that configuration in the context of particular provider is not correct?

@ajcvickers
Copy link
Member

Re-opening to discuss @voroninp's suggestion.

@ajcvickers ajcvickers reopened this Jun 20, 2019
@ajcvickers
Copy link
Member

Note from triage: putting this on the backlog to add TODO comments in the generated migration indicating that EF was not able to implement any store-generation in the implemented migration. Note, however, that if client side generation is being used, then it's fine for the column to not be store-generated.

@ajcvickers ajcvickers added this to the Backlog milestone Jun 24, 2019
@ajcvickers ajcvickers added type-enhancement and removed closed-no-further-action The issue is closed and no further action is planned. labels Jun 24, 2019
@gojanpaolo
Copy link

gojanpaolo commented Nov 30, 2019

Hello, It seems we're hitting a similar issue when using owned entity types with a composite key including an int property with a value of 0.

using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;

namespace ConsoleApp1
{
    internal class Program
    {
        private static void Main()
        {
            var options = new DbContextOptionsBuilder<MyContext>()
                .UseSqlite("datasource=db.sqlite")
                .Options;
            using var ctx = new MyContext(options);
            ctx.Database.EnsureCreated();
            ctx.Add(new Input { Boosters = { new Booster { Index = 0 } } }); // no exception when the index > 0
            ctx.SaveChanges();
        }
    }
    public class MyContext : DbContext
    {
        public MyContext(DbContextOptions options) : base(options) { }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Input>().OwnsMany(i => i.Boosters, b =>
            {
                b.HasKey("InputId", "Index");
            });
        }
    }
    public class Input
    {
        public int InputId { get; set; }
        public ICollection<Booster> Boosters { get; } = new List<Booster>();
    }
    public class Booster
    {
        public int Index { get; set; }
    }
}

Exception

Microsoft.EntityFrameworkCore.DbUpdateException
  HResult=0x80131500
  Message=An error occurred while updating the entries. See the inner exception for details.
  Source=Microsoft.EntityFrameworkCore.Relational
  StackTrace:
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(DbContext _, ValueTuple`2 parameters)
   at Microsoft.EntityFrameworkCore.Storage.Internal.NoopExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IList`1 entries)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IList`1 entriesToSave)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()
   at ConsoleApp1.Program.Main() in C:\deleteme\ef\ConsoleApp1\Program.cs:line 17

  This exception was originally thrown at this call stack:
	Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(int, SQLitePCL.sqlite3)
	Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
	Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(System.Data.CommandBehavior)
	Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReader(System.Data.CommandBehavior)
	System.Data.Common.DbCommand.ExecuteReader()
	Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(Microsoft.EntityFrameworkCore.Storage.RelationalCommandParameterObject)
	Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(Microsoft.EntityFrameworkCore.Storage.IRelationalConnection)

Inner Exception 1:
SqliteException: SQLite Error 19: 'NOT NULL constraint failed: Booster.Index'.

Further technical details

EF Core version: 3.0.1 (also tried 3.1.0-preview3.19554.8)
Database Provider: Microsoft.EntityFrameworkCore.Sqlite
Project: netcoreapp3.1 console app

Workaround

It looks like configuring the int property with ValueGeneratedNever can be a workaround.

modelBuilder.Entity<Input>().OwnsMany(i => i.Boosters, b =>
{
    b.HasKey("InputId", "Index");
    b.Property(b => b.Index).ValueGeneratedNever();
});

@Rwing
Copy link

Rwing commented Dec 27, 2019

@gojanpaolo Thank you very much, It's worked for me.

@NVentimiglia
Copy link

NVentimiglia commented Feb 13, 2020

Ive run into this issue. I am trying to initialize a SQLDatabase and seed it.

SQLite Error 19: 'NOT NULL constraint failed: Freights.UpdatedOn'.

Inspecting my entity I see the UpdatedOn field is set.
Inspecting my db, I see the table created correctly.

I am using a custom OnConfiguring

protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite("Data Source=my.db");

and custom IDesignTimeDbContextFactory with SQLITE

IDesignTimeDbContextFactory

maraf added a commit to neptuo/Recollections that referenced this issue Apr 2, 2020
@AndriySvyryd AndriySvyryd changed the title Getting SQLite Error 19: 'NOT NULL constraint failed: Test.Id' on running test case Add a warning when store-generated PK is not supported Aug 13, 2020
@ChrTall
Copy link

ChrTall commented Jul 29, 2021

@ajcvickers
From the Ef Core Docs:
Depending on the database provider being used, values may be generated client side by EF or in the database.
Does this mean Ef should handle the Auto-increment for Composite PKs when using SQLite ? Right now we would have to create a custom Value Generator. This is a bit of a problem because a lot of people use SQLite in Memory Databases for Unit Tests and it is not straight to figure out what exactly the problem is and why the tests fail.

@RamsLR
Copy link

RamsLR commented Nov 2, 2021

This issue still repros since the generated SQLite table does NOT have autoincrement flag in it. Is there a way to fix the table after it is created just in the case of Sqlite ?

For me, the issure repro'd only when the identity field was also part of an unique index constraint (may be that is not needed?) however when I swapped it to be a primary key the auto-increment annotations were correctly added to the migrations code and the issue is fixed.

@ajcvickers ajcvickers removed this from the Backlog milestone Nov 5, 2021
@ajcvickers ajcvickers modified the milestone: 6.0.x Nov 10, 2021
@ajcvickers ajcvickers added this to the 7.0.0 milestone Nov 10, 2021
@ajcvickers ajcvickers added punted-for-7.0 Originally planned for the EF Core 7.0 (EF7) release, but moved out due to resource constraints. and removed propose-punt labels Jul 7, 2022
@ajcvickers ajcvickers modified the milestones: 7.0.0, Backlog Jul 7, 2022
@ajcvickers ajcvickers modified the milestones: Backlog, 7.0.0 Jul 19, 2022
@ajcvickers ajcvickers assigned ajcvickers and unassigned bricelam Jul 23, 2022
@ajcvickers ajcvickers removed the punted-for-7.0 Originally planned for the EF Core 7.0 (EF7) release, but moved out due to resource constraints. label Jul 28, 2022
ajcvickers added a commit that referenced this issue Jul 28, 2022
@ajcvickers ajcvickers added closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. area-model-building and removed area-migrations labels Jul 28, 2022
@ajcvickers ajcvickers modified the milestones: 7.0.0, 7.0.0-rc1 Jul 29, 2022
@RamsLR
Copy link

RamsLR commented Jul 29, 2022

thank you. glad to hear a warning has been added now.

@ajcvickers ajcvickers modified the milestones: 7.0.0-rc1, 7.0.0 Nov 5, 2022
@ajcvickers ajcvickers removed their assignment Sep 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-model-building closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants