Efcore: Add a warning when store-generated PK is not supported

Created on 6 Mar 2018  路  12Comments  路  Source: dotnet/efcore

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:

```C#
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**

```C#
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

```C#
public async Task CreateTest(TestDetailsDto input)
{
try
{
int TestId = await InsertAndGetIdAsync(ObjectMapper.Map(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.<ExecuteAsync>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.<ExecuteAsync>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.TaskAwaiter`1.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.TaskAwaiter`1.GetResult()
> [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6341641]            at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<SaveChangesAsync>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.TaskAwaiter`1.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.TaskAwaiter`1.GetResult()
> [3/6/2018 5:49:06 AM Informational] [xUnit.net 00:00:26.6371579]            at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.<ExecuteAsync>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.<ExecuteAsync>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:**

```C#
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:

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

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

}

**Usage:**

```C#
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

area-migrations type-enhancement

Most helpful comment

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.

```c#
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;

namespace ConsoleApp1
{
internal class Program
{
private static void Main()
{
var options = new DbContextOptionsBuilder()
.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().OwnsMany(i => i.Boosters, b =>
{
b.HasKey("InputId", "Index");
});
}
}
public class Input
{
public int InputId { get; set; }
public ICollection Boosters { get; } = new List();
}
public class Booster
{
public int Index { get; set; }
}
}

## Exception

```c#
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.

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

All 12 comments

@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?

Yes, migration is generated against sql server. I don鈥檛 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?

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

@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 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);
    }
}

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

@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?

Re-opening to discuss @voroninp's suggestion.

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.

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.

```c#
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;

namespace ConsoleApp1
{
internal class Program
{
private static void Main()
{
var options = new DbContextOptionsBuilder()
.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().OwnsMany(i => i.Boosters, b =>
{
b.HasKey("InputId", "Index");
});
}
}
public class Input
{
public int InputId { get; set; }
public ICollection Boosters { get; } = new List();
}
public class Booster
{
public int Index { get; set; }
}
}

## Exception

```c#
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.

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

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

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

Was this page helpful?
0 / 5 - 0 ratings