Skip to content

Commit 0a616a9

Browse files
CopilotAndriySvyrydroji
authored
Update SQLite AUTOINCREMENT documentation for EF Core 10 (#5115)
Fixes #5101 --------- Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com> Co-authored-by: Shay Rojansky <roji@roji.org>
1 parent 0c5af46 commit 0a616a9

7 files changed

Lines changed: 148 additions & 0 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
title: SQLite Database Provider - Value Generation - EF Core
3+
description: Value Generation Patterns Specific to the SQLite Entity Framework Core Database Provider
4+
author: AndriySvyryd
5+
ms.date: 09/26/2025
6+
uid: core/providers/sqlite/value-generation
7+
---
8+
# SQLite Value Generation
9+
10+
This page details value generation configuration and patterns that are specific to the SQLite provider. It's recommended to first read [the general page on value generation](xref:core/modeling/generated-properties).
11+
12+
## AUTOINCREMENT columns
13+
14+
By convention, numeric primary key columns that are configured to have their values generated on add are set up with [SQLite's AUTOINCREMENT feature](https://sqlite.org/autoinc.html). Starting with EF Core 10, SQLite AUTOINCREMENT can also be enabled or disabled via configuration.
15+
16+
### Configuring AUTOINCREMENT
17+
18+
By convention, integer primary keys are automatically configured with AUTOINCREMENT when they are not part of a composite key and don't have a foreign key on them. However, you may need to explicitly configure a property to use SQLite AUTOINCREMENT when the property has a value conversion from a non-integer type, or when overriding conventions:
19+
20+
[!code-csharp[Main](../../../../samples/core/Sqlite/ValueGeneration/SqliteAutoincrementWithValueConverter.cs?name=SqliteAutoincrementWithValueConverter&highlight=4)]
21+
22+
## Disabling AUTOINCREMENT for default SQLite value generation
23+
24+
AUTOINCREMENT imposes extra CPU, memory, disk space, and disk I/O overhead compared to the default key generation algorithm in SQLite - [ROWID](https://sqlite.org/lang_createtable.html#rowid). The downside of `ROWID` is that it reuses values from deleted rows. If your scenario wouldn't be affected by this, you may want to disable AUTOINCREMENT and use SQLite's default value generation behavior instead. You can do this using the Metadata API:
25+
26+
<!--
27+
protected override void OnModelCreating(ModelBuilder modelBuilder)
28+
{
29+
modelBuilder.Entity<Blog>()
30+
.Property(b => b.Id)
31+
.Metadata.SetValueGenerationStrategy(SqliteValueGenerationStrategy.None);
32+
}
33+
-->
34+
[!code-csharp[Main](../../../../samples/core/Sqlite/ValueGeneration/SqliteValueGenerationStrategyNone.cs?name=SqliteValueGenerationStrategyNone&highlight=5)]
35+
36+
Alternatively, you can configure EF to not treat the property as value-generated:
37+
38+
<!--
39+
protected override void OnModelCreating(ModelBuilder modelBuilder)
40+
{
41+
modelBuilder.Entity<Blog>()
42+
.Property(b => b.Id)
43+
.ValueGeneratedNever();
44+
}
45+
-->
46+
[!code-csharp[Main](../../../../samples/core/Sqlite/ValueGeneration/SqliteValueGeneratedNever.cs?name=SqliteValueGeneratedNever&highlight=5)]
47+
48+
This means that it's up to the application to supply a value for the property before saving to the database. Note that this still won't disable the default value generation server-side, so non-EF usages could still get a generated value. To [completely disable value generation](https://sqlite.org/lang_createtable.html#rowids_and_the_integer_primary_key), change the column type from `INTEGER` to `INT`.

entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ If `fieldName` is trusted or has been properly sanitized, the warning can be saf
687687

688688
## Other improvements
689689

690+
- AUTOINCREMENT can now be disabled for SQLite and is also supported for properties with value converters. For more information, see [SQLite Value Generation](xref:core/providers/sqlite/value-generation).
690691
- Stop spanning all migrations with a single transaction ([#35096](https://github.com/dotnet/efcore/issues/35096)). This reverts a change done in EF9 which caused issues in various migration scenarios.
691692
- Make SQL Server scaffolding compatible with Azure Data Explorer ([#34832](https://github.com/dotnet/efcore/pull/34832), contributed by [@barnuri](https://github.com/barnuri)).
692693
- Associate the DatabaseRoot with the scoped options instance and not the singleton options ([#34477](https://github.com/dotnet/efcore/pull/34477), contributed by [@koenigst](https://github.com/koenigst)).

entity-framework/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,8 @@
425425
href: core/providers/sqlite/limitations.md
426426
- name: Function mappings
427427
href: core/providers/sqlite/functions.md
428+
- name: Value generation
429+
href: core/providers/sqlite/value-generation.md
428430
- name: Spatial data
429431
displayName: GIS
430432
href: core/providers/sqlite/spatial.md
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using Microsoft.EntityFrameworkCore;
2+
3+
namespace EFCore.Sqlite.ValueGeneration;
4+
5+
public readonly struct BlogId
6+
{
7+
public BlogId(int value) => Value = value;
8+
public int Value { get; }
9+
10+
public static implicit operator int(BlogId id) => id.Value;
11+
public static implicit operator BlogId(int value) => new(value);
12+
}
13+
14+
public class SqliteAutoincrementWithValueConverterContext : DbContext
15+
{
16+
public DbSet<Blog> Blogs { get; set; }
17+
18+
#region SqliteAutoincrementWithValueConverter
19+
protected override void OnModelCreating(ModelBuilder modelBuilder)
20+
{
21+
modelBuilder.Entity<Blog>()
22+
.Property(b => b.Id)
23+
.HasConversion<int>()
24+
.UseAutoincrement();
25+
}
26+
#endregion
27+
28+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
29+
=> optionsBuilder.UseSqlite("Data Source=sample.db");
30+
}
31+
32+
public class Blog
33+
{
34+
public BlogId Id { get; set; }
35+
public string Title { get; set; }
36+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Microsoft.EntityFrameworkCore;
2+
3+
namespace EFCore.Sqlite.ValueGeneration;
4+
5+
public class SqliteValueGeneratedNeverContext : DbContext
6+
{
7+
public DbSet<Blog> Blogs { get; set; }
8+
9+
#region SqliteValueGeneratedNever
10+
protected override void OnModelCreating(ModelBuilder modelBuilder)
11+
{
12+
modelBuilder.Entity<Blog>()
13+
.Property(b => b.Id)
14+
.ValueGeneratedNever();
15+
}
16+
#endregion
17+
18+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
19+
=> optionsBuilder.UseSqlite("Data Source=sample.db");
20+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>disable</Nullable>
7+
<OutputType>Library</OutputType>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.0-rc.1.25451.107" />
12+
</ItemGroup>
13+
14+
</Project>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.EntityFrameworkCore.Sqlite.Metadata;
3+
4+
namespace EFCore.Sqlite.ValueGeneration;
5+
6+
public class SqliteValueGenerationStrategyNoneContext : DbContext
7+
{
8+
public DbSet<Blog> Blogs { get; set; }
9+
10+
#region SqliteValueGenerationStrategyNone
11+
protected override void OnModelCreating(ModelBuilder modelBuilder)
12+
{
13+
modelBuilder.Entity<Blog>()
14+
.Property(b => b.Id)
15+
.Metadata.SetValueGenerationStrategy(SqliteValueGenerationStrategy.None);
16+
}
17+
#endregion
18+
19+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
20+
=> optionsBuilder.UseSqlite("Data Source=sample.db");
21+
}
22+
23+
public class Blog
24+
{
25+
public int Id { get; set; }
26+
public string Title { get; set; }
27+
}

0 commit comments

Comments
 (0)