Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions entity-framework/core/providers/sqlite/value-generation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: SQLite Database Provider - Value Generation - EF Core
description: Value Generation Patterns Specific to the SQLite Entity Framework Core Database Provider
author: AndriySvyryd
ms.date: 09/26/2025
uid: core/providers/sqlite/value-generation
---
# SQLite Value Generation

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).

## AUTOINCREMENT columns

By convention, numeric primary key columns that are configured to have their values generated on add are set up with SQLite's AUTOINCREMENT feature. Starting with EF Core 10, SQLite AUTOINCREMENT is a first-class feature with full support through conventions and the Fluent API.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link to the SQLite doc page explaining what AUTOINCREMENT is.

I'm not sure what the 2nd sentence exactly means for the user... I'd maybe instead have a small Limitations sections at the bottom of the page listing the concrete problems that existed before EF 10, but as it is this sentence doesn't actually seem to tell the user anything concrete.


### Configuring AUTOINCREMENT

By convention, integer primary keys are automatically configured with AUTOINCREMENT when they are not composite 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:

[!code-csharp[Main](../../../../samples/core/Sqlite/ValueGeneration/SqliteAutoincrementWithValueConverter.cs?name=SqliteAutoincrementWithValueConverter&highlight=6)]

## Disabling AUTOINCREMENT for default SQLite value generation

In some cases, you may want to disable AUTOINCREMENT and use SQLite's default value generation behavior instead. You can do this using the Metadata API:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just add a few words on when/why someone would want this (or at least link to the docs)? Otherwise that's just documenting our APIs without their meaning/why they exist.


[!code-csharp[Main](../../../../samples/core/Sqlite/ValueGeneration/SqliteValueGenerationStrategyNone.cs?name=SqliteValueGenerationStrategyNone&highlight=5)]

Starting with EF Core 10, you can also use the strongly-typed Metadata API:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the preview, the inline code snippet just below seems identical to the one linked to just above (the external linking makes this quite hard to notice when reviewing, FWIW). Accidental duplication?


```csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.Property(p => p.Id)
.Metadata.SetValueGenerationStrategy(SqliteValueGenerationStrategy.None);
}
```

Alternatively, you can disable value generation entirely:

```csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Id)
.ValueGeneratedNever();
}
```

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 the user can change the column type from `INTEGER` to `INT`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


## Migration behavior

When EF Core generates migrations for SQLite AUTOINCREMENT columns, the generated migration will include the `Sqlite:Autoincrement` annotation:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is internal implementation details which IMHO doesn't belong here (we don't do this for any other features anywhere else in the docs).


```csharp
migrationBuilder.CreateTable(
name: "Blogs",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Title = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Blogs", x => x.Id);
});
```

This ensures that the AUTOINCREMENT feature is properly applied when the migration is executed against the SQLite database.
10 changes: 10 additions & 0 deletions entity-framework/core/what-is-new/ef-core-10.0/whatsnew.md
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,16 @@ await context.Blogs.ExecuteUpdateAsync(s =>

Thanks to [@aradalvand](https://github.com/aradalvand) for proposing and pushing for this change (in [#32018](https://github.com/dotnet/efcore/issues/32018)).

<a name="sqlite"></a>

## SQLite

### Improved AUTOINCREMENT support

SQLite AUTOINCREMENT is now a first-class feature with full support through conventions and the Fluent API. Previously, properties with value converters couldn't configure AUTOINCREMENT and would cause false pending model change warnings.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, the actual user-facing improvement (or at least the main one) is us properly supporting autoincrement on value-converted properties (the rest of it doesn't seem very user-facing). IMHO this merits a one-line bullet below under improvements, rather than a whole top-level "SQLite" section which then contains only this.


For more information, see [SQLite Value Generation](xref:core/providers/sqlite/value-generation).

<a name="other-improvements"></a>

## Other improvements
Expand Down
2 changes: 2 additions & 0 deletions entity-framework/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,8 @@
href: core/providers/sqlite/limitations.md
- name: Function mappings
href: core/providers/sqlite/functions.md
- name: Value generation
href: core/providers/sqlite/value-generation.md
- name: Spatial data
displayName: GIS
href: core/providers/sqlite/spatial.md
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Microsoft.EntityFrameworkCore;

namespace EFCore.Sqlite.ValueGeneration;

public readonly struct BlogId
{
public BlogId(int value) => Value = value;
public int Value { get; }

public static implicit operator int(BlogId id) => id.Value;
public static implicit operator BlogId(int value) => new(value);
}

public class SqliteAutoincrementWithValueConverterContext : DbContext
{
public DbSet<BlogPost> Blogs { get; set; }

#region SqliteAutoincrementWithValueConverter
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BlogPost>()
.Property(b => b.Id)
.HasConversion<int>()
.UseAutoincrement();
}
#endregion

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlite("Data Source=sample.db");
}

public class BlogPost
{
public BlogId Id { get; set; }
public string Title { get; set; }
}
14 changes: 14 additions & 0 deletions samples/core/Sqlite/ValueGeneration/SqliteValueGeneration.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<OutputType>Library</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.0-rc.1.25451.107" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Sqlite.Metadata;

namespace EFCore.Sqlite.ValueGeneration;

public class SqliteValueGenerationStrategyNoneContext : DbContext
{
public DbSet<Post> Posts { get; set; }

#region SqliteValueGenerationStrategyNone
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.Property(p => p.Id)
.Metadata.SetValueGenerationStrategy(SqliteValueGenerationStrategy.None);
}
#endregion

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlite("Data Source=sample.db");
}

public class Post
{
public int Id { get; set; }
public string Content { get; set; }
}
5 changes: 5 additions & 0 deletions samples/global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"sdk": {
"version": "10.0.100-rc.1.25451.107"
}
}
Loading