Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This page documents API and behavior changes that have the potential to break existing applications updating from EF Core 10 to EF Core 11. Make sure to review earlier breaking changes if updating from an earlier version of EF Core:
Summary
Note
If you are using Microsoft.Data.Sqlite, please see the separate section below on Microsoft.Data.Sqlite breaking changes.
High-impact changes
Cosmos: Unmapped properties are no longer preserved
Old behavior
Previously, when EF Core read a Cosmos DB document that contained JSON properties not mapped in the EF model, those extra properties were preserved in the __jObject shadow property and written back to the database on the next SaveChanges. Unmapped data in documents was transparently round-tripped.
New behavior
Starting with EF Core 11, unmapped JSON properties in a Cosmos DB document are ignored when reading. Any extra properties that are not part of the EF model will be lost if the entity is subsequently saved.
Why
Because __jObject has been removed (see Cosmos: __jObject shadow property removed; JObject no longer used for serialization), there is no mechanism to preserve unmapped properties. EF Core 11 uses a lean JSON reader that only processes the properties it knows about from the model.
Mitigations
If your application relies on preserving unmapped data, consider one of the following options:
- Use
CosmosClientdirectly for documents where you need full control over the JSON shape. - Map all relevant properties explicitly in your EF model, including any extra fields that should be preserved.
Medium-impact changes
Sync I/O via the Azure Cosmos DB provider has been fully removed
Old behavior
Synchronous I/O via the Azure Cosmos DB provider has been unsupported since EF 9.0 (note); calling any sync I/O API - like ToList or SaveChanges threw an exception, unless a special opt-in was configured. When the opt-in was configured, sync I/O APIs worked as before, causing the provider to perform "sync-over-async" blocking against the Azure Cosmos DB SDK, which could result in deadlocks and other performance issues.
New behavior
Starting with EF Core 11.0, EF now always throws when a synchronous I/O API is called. There is no way to opt back into using sync I/O APIs.
Why
Synchronous blocking on asynchronous methods ("sync-over-async") is highly discouraged, and can lead to deadlock and other performance problems. Since the Azure Cosmos DB SDK only supports async methods, so does the EF Cosmos provider.
Mitigations
Convert your code to use async I/O APIs instead of sync I/O ones. For example, replace calls to SaveChanges() with await SaveChangesAsync().
Microsoft.Data.SqlClient has been updated to 7.0
Old behavior
EF Core 10 used Microsoft.Data.SqlClient 6.x, which included Azure/Entra ID authentication dependencies (such as Azure.Core, Azure.Identity, and Microsoft.Identity.Client) in the core package.
New behavior
EF Core 11 now depends on Microsoft.Data.SqlClient 7.0. This version removes Azure/Entra ID (formerly Azure Active Directory) authentication dependencies from the core package. If your application uses Entra ID authentication (for example, ActiveDirectoryDefault, ActiveDirectoryInteractive, ActiveDirectoryManagedIdentity, or ActiveDirectoryServicePrincipal), you must now install the Microsoft.Data.SqlClient.Extensions.Azure package separately.
In addition, SqlAuthenticationMethod.ActiveDirectoryPassword has been marked as obsolete.
For more details, see the Microsoft.Data.SqlClient 7.0 release notes.
Why
This change was made in Microsoft.Data.SqlClient to reduce dependency bloat for applications that don't use Azure authentication, which is especially beneficial for containerized deployments and local development.
Mitigations
If your application uses Entra ID authentication with SQL Server, add a reference to the Microsoft.Data.SqlClient.Extensions.Azure package in your project:
<PackageReference Include="Microsoft.Data.SqlClient.Extensions.Azure" Version="7.0.0" />
No code changes are required beyond adding this package reference. If you use SqlAuthenticationMethod.ActiveDirectoryPassword, migrate to a modern authentication method such as ActiveDirectoryDefault or ActiveDirectoryInteractive.
Cosmos: illegal id characters are no longer escaped
Old behavior
Previously, when generating the Cosmos id property value from a composite key that contains multiple parts, the Azure Cosmos DB provider escaped certain characters that are illegal in Cosmos resource id values:
| Character | Escaped as |
|---|---|
/ |
^2F |
\ |
^5C |
? |
^3F |
# |
^23 |
New behavior
Starting with EF Core 11.0, these characters are no longer escaped in the generated id value. The id value will contain the raw key values without modification. Note that when id values are concatenated (i.e. when using a composite key or when the discriminator-in-id behavior is opted into), the | character is used as a separator—and any | characters already present in key values are escaped to avoid ambiguity. No other escaping is applied.
The old escape behavior can be re-enabled by setting an AppContext switch:
AppContext.SetSwitch("Microsoft.EntityFrameworkCore.EscapeIllegalCosmosIdCharacters", true);
Why
The previous escaping scheme was non-injective: the escape character ^ was never itself escaped. This meant that a key value containing the literal string ^2F would produce the same id as a key value containing /, resulting in silent data corruption where two entities with distinct primary keys would be mapped to the same Cosmos document. Stopping the escaping altogether fixes the collision problem.
Mitigations
If your application uses composite keys whose values can contain the characters /, \, ?, or #, be aware of the following:
- Existing data: Documents previously stored in Cosmos DB have
idvalues using the old escape sequences (e.g.Post|1|^2F). After upgrading to EF Core 11, EF will generate unescapedidvalues (e.g.Post|1|/) and will no longer find those existing documents. To continue accessing existing data without migration, opt back into the old behavior using theAppContextswitch described above—however, be aware that the id-collision bug will still be present. - New data: If you are creating a new application or database, avoid using these illegal characters in key values, as they are not valid in Cosmos DB resource
idvalues. See the Azure documentation for details.
Cosmos: exception thrown when a projection evaluates to undefined
Old behavior
Previously, when projecting properties in anonymous type or DTO projections via navigation over optional relationships where a segment of the path was absent in the Cosmos DB document (causing the projected value to be undefined), the behavior was inconsistent:
- With single-property anonymous type or DTO projections, EF translated the query using
SELECT VALUE, which silently filtered out any documents where the projected value wasundefined. This meant fewer results were returned than expected, with no indication of the missing data. - With multi-property anonymous type or DTO projections, an
InvalidOperationExceptionwith the message "Nullable object must have a value" was thrown.
For example, given an entity Entity with an optional owned Associate which in turn has an optional owned NestedAssociate:
// Previously silently returned fewer results (undefined results were filtered out)
var singlePropResults = await context.Entities
.Select(x => new { x.Associate!.NestedAssociate!.Id })
.ToListAsync();
// Previously threw InvalidOperationException: Nullable object must have a value
var multiPropResults = await context.Entities
.Select(x => new { x.Associate!.NestedAssociate!.Id, x.Associate!.NestedAssociate!.String })
.ToListAsync();
New behavior
Starting with EF Core 11.0, an InvalidOperationException is thrown in both cases when any part of the projection evaluates to undefined in Azure Cosmos DB. The exception message is:
A part of the projection was undefined, use the coalesce operator to handle possible undefined values.
Why
The previous behavior was inconsistent. Single-property projections could silently discard results, making it easy to miss data without any indication of the problem. The new behavior ensures consistent, predictable error reporting whenever a projection encounters an undefined value.
Mitigations
Use IsDefined to filter out documents where the projected value is missing:
var results = await context.Entities
.Where(x => EF.Functions.IsDefined(x.Associate!.NestedAssociate!.Id))
.Select(x => new { x.Associate!.NestedAssociate!.Id })
.ToListAsync();
Alternatively, use CoalesceUndefined to provide a default value for properties that could be undefined:
var results = await context.Entities
.Select(x => new
{
Id = EF.Functions.CoalesceUndefined(x.Associate!.NestedAssociate!.Id, Guid.Empty)
})
.ToListAsync();
Low-impact changes
Cosmos: __jObject shadow property removed; JObject no longer used for serialization
Old behavior
Previously, the Azure Cosmos DB provider added a shadow property named "__jObject" of type JObject (from Newtonsoft.Json) to every entity type. This property contained the raw JSON document as received from and sent to Cosmos DB, allowing access to unmapped or raw data:
var order = await context.Orders.FirstAsync();
var rawJson = context.Entry(order).Property<JObject>("__jObject").CurrentValue;
var billingAddress = rawJson["BillingAddress"]?.Value<string>();
EF Core used Newtonsoft.Json (via JObject) internally for all document serialization and deserialization.
New behavior
Starting with EF Core 11, the __jObject shadow property no longer exists. EF Core now uses System.Text.Json (Utf8JsonReader/Utf8JsonWriter) for document serialization and deserialization, and no longer depends on Newtonsoft.Json.
Accessing the "__jObject" property will throw an InvalidOperationException.
Why
The JObject-based approach required a dependency on Newtonsoft.Json and limited performance improvements. Switching to System.Text.Json aligns EF Core Cosmos with the rest of the .NET ecosystem and enables significant performance gains in the materializer.
Mitigations
To access the raw JSON document, use the CosmosClient directly instead of relying on __jObject:
var cosmosClient = context.Database.GetCosmosClient();
var container = cosmosClient.GetContainer("myDatabase", "myContainer");
var response = await container.ReadItemAsync<JsonElement>("1", new PartitionKey("1"));
var billingAddress = response.Resource.GetProperty("BillingAddress").GetString();
For more information, see Working with Unstructured Data in Azure Cosmos DB.
SQL Server compatibility level now defaults to 160
Old behavior
Previously, when using UseSqlServer without explicitly configuring a SQL Server compatibility level, EF Core defaulted to compatibility level 150, corresponding to SQL Server 2019.
New behavior
Starting with EF Core 11.0, UseSqlServer defaults to compatibility level 160, corresponding to SQL Server 2022. This allows EF to generate SQL which uses SQL Server 2022 features by default. For example, some queries now use LEAST and GREATEST, including translations for Math.Min, Math.Max, Least, Greatest, and some Take/Skip patterns.
If your database runs on SQL Server 2019 or older, or is configured with a compatibility level lower than 160, some SQL generated by EF Core may no longer be supported by the database.
Why
SQL Server 2022 has been available for several years, and using compatibility level 160 by default allows EF Core to generate simpler and more efficient SQL for newer SQL Server versions.
Mitigations
If your database does not support compatibility level 160, configure EF Core to use the compatibility level supported by your database:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("<connection string>", o => o.UseCompatibilityLevel(150));
}
For more information, see the SQL Server compatibility level documentation.
EF Core now throws by default when no migrations are found
Old behavior
Previously, when calling Migrate or MigrateAsync on a database with no migrations in the assembly, EF Core logged an informational message and returned without applying any changes.
New behavior
Starting with EF Core 11.0, EF Core throws an exception by default when no migrations are found in the assembly. This is consistent with the PendingModelChangesWarning behavior introduced in EF 9.0.
Why
Calling Migrate() or MigrateAsync() when no migrations exist typically indicates a misconfiguration. Rather than silently continuing and leaving the database in a potentially incorrect state, EF Core now alerts developers to this issue immediately.
Mitigations
If you intentionally call Migrate() without having any migrations (for example, because you manage the database schema through other means), remove the Migrate() call or suppress the exception by configuring warnings:
options.ConfigureWarnings(w => w.Ignore(RelationalEventId.MigrationsNotFound))
Or to log the event instead of throwing:
options.ConfigureWarnings(w => w.Log(RelationalEventId.MigrationsNotFound))
EFOptimizeContext MSBuild property has been removed
Old behavior
Previously, the EFOptimizeContext MSBuild property could be set to true to enable compiled model and precompiled query code generation during build or publish:
<EFOptimizeContext Condition="'$(Configuration)'=='Release'">true</EFOptimizeContext>
New behavior
Starting with EF Core 11.0, the EFOptimizeContext MSBuild property has been removed. Code generation is now controlled exclusively through the EFScaffoldModelStage and EFPrecompileQueriesStage properties. When PublishAOT is set to true, code generation is automatically enabled during publish without needing any additional property.
Why
The EFScaffoldModelStage and EFPrecompileQueriesStage properties already provide fine-grained control over when code generation occurs. EFOptimizeContext was a redundant enablement gate.
Mitigations
Replace usages of EFOptimizeContext with the EFScaffoldModelStage and EFPrecompileQueriesStage properties. These can be set to publish or build to control at which stage code generation occurs:
<EFScaffoldModelStage>publish</EFScaffoldModelStage>
<EFPrecompileQueriesStage>publish</EFPrecompileQueriesStage>
Any other value (for example, none) disables the corresponding generation.
If you have PublishAOT set to true, code generation is automatically enabled during publish and no additional configuration is needed.
EF tools packages no longer reference Microsoft.EntityFrameworkCore.Design
Old behavior
Previously, the Microsoft.EntityFrameworkCore.Tools and Microsoft.EntityFrameworkCore.Tasks NuGet packages had a dependency on Microsoft.EntityFrameworkCore.Design.
New behavior
Starting with EF Core 11.0, the Microsoft.EntityFrameworkCore.Tools and Microsoft.EntityFrameworkCore.Tasks NuGet packages no longer have a dependency on Microsoft.EntityFrameworkCore.Design.
Why
There was no hard dependency on the code in Microsoft.EntityFrameworkCore.Design, and this dependency was causing issues when using the latest Microsoft.EntityFrameworkCore.Tools with projects targeting older frameworks.
Mitigations
If your project relies on Microsoft.EntityFrameworkCore.Design being brought in transitively through the tools packages, add a direct reference to it in your project:
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="11.0.0" PrivateAssets="all" />
SqlVector properties are no longer loaded by default
Old behavior
Previously, when querying entities with SqlVector<T> properties, EF Core included the vector column in SELECT statements and populated the property on the returned entity.
New behavior
Starting with EF Core 11.0, SqlVector<T> properties are no longer included in SELECT statements when materializing entities. The property will be null on returned entities.
Vector properties can still be used in WHERE and ORDER BY clauses—including with VectorDistance() and VectorSearch(); they just won't be included in the entity projection.
Why
Vector columns can be very large, containing hundreds or thousands of floating-point values. In the vast majority of cases, vectors are written to the database and then used for search, without needing to be read back. Excluding them from SELECT by default avoids unnecessary data transfer.
Mitigations
Note
A mechanism for opting vector properties back into automatic loading will be introduced later in the EF Core 11 release.
If you need to read back vector values, use an explicit projection:
var embeddings = await context.Blogs
.Select(b => new { b.Id, b.Embedding })
.ToListAsync();
Cosmos: empty owned collections now return an empty collection instead of null
Old behavior
Previously, when querying entities via the Azure Cosmos DB provider where an owned collection contained no items, the collection property was null on the materialized entity.
New behavior
Starting with EF Core 11.0, the Azure Cosmos DB provider correctly initializes empty owned collections, returning an empty collection instead of null.
Why
The previous behavior of materializing empty owned collections as null was a bug.
Mitigations
If your code explicitly checks owned collection properties for null to detect that the collection is empty, those checks can simply be removed, since the collection is now always initialized:
// Before
if (entity.OwnedCollection is null or { Count: 0 })
{
// treated as empty
}
// After
if (entity.OwnedCollection is { Count: 0 })
{
// treated as empty
}
Cosmos: the default discriminator property is now named Discriminator in the model
Old behavior
EF automatically adds a discriminator property to identify the entity type that a JSON document represents. The name of this property in the JSON document was changed from Discriminator to $type in EF Core 9.0. To achieve this, EF used $type as the name of the discriminator property both in the EF model and in the stored JSON document.
Because $type is not a valid C# identifier, the resulting shadow property name caused invalid code to be generated for compiled models and precompiled queries used with Native AOT.
New behavior
Starting with EF Core 11.0, the default discriminator property is once again named Discriminator in the EF model, while the name written to the JSON document is unchanged and remains $type by default. In other words, the model property name and the JSON property name are now decoupled:
entityType.FindDiscriminatorProperty().NamereturnsDiscriminator.entityType.FindDiscriminatorProperty().GetJsonPropertyName()returns$type.
The format of the stored documents is not affected by this change, so existing data continues to work without modification.
Why
EF derives some generated C# identifiers (for example, shadow property variable names) from model metadata such as property names. Since $type is not a valid C# identifier, using it as the model property name produced uncompilable code for compiled models and precompiled queries. Naming the model property Discriminator (a valid identifier) while still writing $type to the document keeps generated code valid without changing the on-disk format.
Mitigations
For most applications no action is needed, since stored documents are unaffected and continue to use $type.
If your code references the discriminator by its model property name, $type (for example, via Property in a query or query filter, or by looking the property up in the metadata), update it to use Discriminator instead:
// Before
var query = context.Set<Session>().Where(e => EF.Property<string>(e, "$type") == "Lecture");
// After
var query = context.Set<Session>().Where(e => EF.Property<string>(e, "Discriminator") == "Lecture");
To change the JSON discriminator property name for the whole model in a single place--for example, to align it with the model property name--use the model-level HasEmbeddedDiscriminatorName API instead of configuring each entity type individually:
modelBuilder.HasEmbeddedDiscriminatorName("Discriminator");
To change only the JSON name for a specific entity type--for example, to align it with the model property name--configure the discriminator property's JSON name with ToJsonProperty:
modelBuilder.Entity<Session>().Property<string>("Discriminator").ToJsonProperty("Discriminator");
To restore the previous behavior where the discriminator property is also named $type in the model, configure its name explicitly with HasDiscriminator. Note that this reintroduces an invalid C# identifier and is not recommended when using compiled models or precompiled queries:
modelBuilder.Entity<Session>().HasDiscriminator<string>("$type");
Cosmos: Floating-point values are now truncated when materializing to fixed-point types
Old behavior
Previously, when a query projection returned a floating-point value (e.g., the result of a numeric expression such as 3 / 4 returned by Cosmos as 0.75) and the target property was a fixed-point type (int, long, decimal, etc.), EF Core would round the value. For example, 0.75 would materialize as 1.
New behavior
Starting with EF Core 11, such values are truncated instead of rounded. 0.75 now materializes as 0, matching standard .NET integer truncation behavior ((int)0.75 == 0).
Why
Truncation is the standard .NET behavior for explicit numeric conversions and is consistent with how other providers behave. The previous rounding behavior was a bug.
Mitigations
If you relied on the previous rounding behavior, apply explicit rounding in your queries using Math.Round:
var result = await context.Products
.Select(p => (int)Math.Round((double)p.Int / (p.Int + 1)))
.SingleAsync();
Owned JSON collections without an explicit key are obsolete
Old behavior
Previously, owned entity types mapped to a JSON column via ToJson could be used as collections without configuring an explicit primary key. EF Core would synthesize an ordinal (positional) key behind the scenes to identify each item in the collection:
public class Blog
{
public int Id { get; set; }
public List<Post> Posts { get; set; } = new();
}
public class Post
{
// No key property
public required string Title { get; set; }
public required string Content { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().OwnsMany(b => b.Posts, b => b.ToJson());
New behavior
Starting with EF Core 11.0, configuring an owned JSON collection without an explicit key produces an OwnedEntityMappedToJsonCollectionWarning warning. The mapping continues to work, but is now considered deprecated and is expected to be removed in a future release.
Owned JSON entities that have an explicit primary key, as well as non-collection owned JSON references, are not affected by this change.
Why
Complex types became fully supported in EF Core 10, including for JSON mapping. Complex types are a better fit than owned types for JSON documents: they have value semantics and no identity, which avoids many of the issues that come from using owned entity types—which are entity types—to model what is fundamentally a value embedded in another document. In particular, owned JSON collections without an explicit key relied on a synthetic ordinal key, which has known limitations and corner cases.
Mitigations
The recommended mitigation is to migrate the type to a complex type, which is now the preferred way to map types to JSON:
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().ComplexCollection(b => b.Posts, b => b.ToJson());
Alternatively, if you need to keep the owned-type mapping, configure a non-shadow primary key on the owned type. Once a key is configured, the warning no longer applies:
public class Post
{
public int Id { get; set; }
public required string Title { get; set; }
public required string Content { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().OwnsMany(b => b.Posts, b =>
{
b.ToJson();
b.HasKey(p => p.Id);
});
If you cannot migrate immediately, you can suppress the warning via ConfigureWarnings:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.ConfigureWarnings(w => w.Ignore(CoreEventId.OwnedEntityMappedToJsonCollectionWarning));
Property no longer configures primitive collections
Old behavior
Previously, calling Property for a member whose CLR type is a collection (for example List<int>) could result in the member being configured as a primitive collection, because a property could be promoted to a primitive collection at model finalization based on its type.
New behavior
Starting with EF Core 11.0, whether a property is a primitive collection is determined entirely when the property is configured. A primitive collection must be configured with PrimitiveCollection (or discovered as one by convention). Property now always configures the member as a non-collection (scalar) property, and there is no longer any finalization-time promotion to a primitive collection.
Why
Treating the element type as a finalization-time concern led to inconsistencies and bugs. For example, a property could be discovered as a primitive collection, but later resolve to a scalar via an inherited value converter, leaving a stale element type that caused an InvalidCastException at model finalization. Making primitive collections a creation-time concern also makes mapping unambiguous in cases like byte[], where it is otherwise unclear whether the member should be mapped as a binary scalar or as a collection of bytes.
Mitigations
If you relied on Property to configure a primitive collection, switch to PrimitiveCollection instead:
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().PrimitiveCollection(b => b.Tags);
In most cases no change is required, since primitive collections are discovered by convention.
Split queries now throw when concurrent modifications are detected
Old behavior
Previously, when a split query (using AsSplitQuery()) encountered out-of-order or orphaned child rows caused by concurrent data modifications between the split query's SQL statements, EF Core silently discarded the affected child collections. The result was an entity with an empty collection even though the related rows still existed—no exception was thrown and no warning was logged.
New behavior
Starting with EF Core 11.0, EF Core throws a DbQueryConcurrencyException when split query results cannot be correlated because of concurrent data modifications. The exception message describes the situation and suggests remediation:
The results of a split query could not be correlated because the data was modified concurrently while the query was executing. Re-execute the query, or execute it within a serializable or snapshot transaction to prevent concurrent modifications.
Why
Silently returning incorrect data (empty collections for entities that have related rows) is far worse than surfacing an error. This scenario is intrinsically caused by the lack of data-consistency guarantees in split queries when the database is modified between statements. Throwing a retriable exception makes the problem visible and gives callers a clear path to recovery.
Mitigations
The simplest mitigation is to re-execute the query; the concurrent modification is transient and the retry will typically succeed:
const int maxRetries = 3;
List<Blog> blogs;
for (var attempt = 0; attempt < maxRetries; attempt++)
{
try
{
blogs = await context.Blogs
.Include(b => b.Posts)
.AsSplitQuery()
.ToListAsync();
break;
}
catch (DbQueryConcurrencyException) when (attempt < maxRetries - 1)
{
// Retry on concurrent modification
}
}
Alternatively, wrap the split query in a serializable or snapshot transaction to prevent concurrent modifications from affecting the results:
await using var transaction =
await context.Database.BeginTransactionAsync(IsolationLevel.Serializable);
var blogs = await context.Blogs
.Include(b => b.Posts)
.AsSplitQuery()
.ToListAsync();
await transaction.CommitAsync();
If neither retry nor a transaction is acceptable, switch to a single query (AsSingleQuery()) which is always consistent:
var blogs = await context.Blogs
.Include(b => b.Posts)
.AsSingleQuery()
.ToListAsync();
Microsoft.Data.Sqlite breaking changes
Note
SQLitePCLRaw is an external, community-maintained library that is not owned or maintained by Microsoft. Microsoft.Data.Sqlite depends on it for its SQLite connectivity.
Summary
| Breaking change | Impact |
|---|---|
| Microsoft.Data.Sqlite no longer supports .NET Framework | Medium |
| Some SQLitePCLRaw bundle packages are no longer maintained | Medium |
| SQLite no longer supports UWP and classic Xamarin | Low |
Medium-impact changes
Microsoft.Data.Sqlite no longer supports .NET Framework
Old behavior
Previously, Microsoft.Data.Sqlite and Microsoft.Data.Sqlite.Core targeted netstandard2.0, which allowed them to be used from .NET Framework applications.
New behavior
Starting with Microsoft.Data.Sqlite 11.0, both packages target net10.0 only. .NET Framework applications can no longer reference or use Microsoft.Data.Sqlite 11.0.
Why
The netstandard2.0 target made older, unsupported .NET targets appear to be supported, and it also masked API differences such as DateOnly and TimeOnly support. Targeting the minimum supported .NET version explicitly makes the supported platform surface clear.
Mitigations
If possible, move the application to .NET 10 or later.
If you must remain on .NET Framework, stay on the latest Microsoft.Data.Sqlite 10.0.x servicing release. The 10.0.x line uses SQLitePCLRaw.bundle_e_sqlite3, allowing .NET Framework applications to update the referenced SQLitePCLRaw.bundle_e_sqlite3 version even after Microsoft.Data.Sqlite stops receiving updates.
Some SQLitePCLRaw bundle packages are no longer maintained
Old behavior
Previously, the SQLitePCLRaw.bundle_e_sqlcipher, SQLitePCLRaw.bundle_sqlite3, SQLitePCLRaw.bundle_winsqlite3, SQLitePCLRaw.bundle_green, and SQLitePCLRaw.bundle_e_sqlite3mc packages provided a convenient way to configure SQLitePCLRaw with the corresponding SQLite provider.
New behavior
The SQLitePCLRaw.bundle_e_sqlcipher, SQLitePCLRaw.bundle_sqlite3, SQLitePCLRaw.bundle_winsqlite3, SQLitePCLRaw.bundle_green, and SQLitePCLRaw.bundle_e_sqlite3mc packages are no longer updated by the SQLitePCLRaw maintainer. They are not compatible with SQLitePCLRaw.Core 3.0 and later, so applications that directly reference any of these packages alongside SQLitePCLRaw.Core 3.x will encounter conflicts. Applications should migrate to the recommended alternatives to avoid future breakage.
Why
The SQLitePCLRaw maintainer removed these bundles in version 3.0; each bundle contained only a single line of configuration code and added unnecessary packaging overhead while the underlying provider packages continue to be supported. The SQLitePCLRaw.bundle_e_sqlcipher package is particularly affected: it provided encryption-enabled builds that are barely maintained, which is a security concern for encryption software where vulnerabilities may go unpatched.
Mitigations
If using SQLitePCLRaw.bundle_e_sqlcipher (encryption-enabled SQLite), migrate to one of the following alternatives:
SQLite3 Multiple Ciphers: NuGet packages are available from SQLite3MultipleCiphers-NuGet. Reference
Microsoft.Data.Sqlite.Coretogether withSQLite3MC.PCLRaw.bundle:<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="11.0.0" /> <PackageReference Include="SQLite3MC.PCLRaw.bundle" Version="2.x.x" />When encrypting a new database or opening an existing database that was encrypted with SQLCipher, configure the cipher scheme using URI parameters—for example:
Data Source=file:example.db?cipher=sqlcipher&legacy=4. See How to open an existing database encrypted with SQLCipher for details.SQLite Encryption Extension (SEE): The official encryption implementation from the SQLite team. A paid license is required. See https://sqlite.org/com/see.html and SourceGear's SQLite build service for NuGet options.
SQLCipher: Purchase supported builds from Zetetic, or build the open source code yourself.
If using SQLitePCLRaw.bundle_sqlite3 or SQLitePCLRaw.bundle_winsqlite3, replace the bundle package with the corresponding provider package:
<!-- Old -->
<PackageReference Include="SQLitePCLRaw.bundle_sqlite3" Version="2.x.x" />
<!-- or -->
<PackageReference Include="SQLitePCLRaw.bundle_winsqlite3" Version="2.x.x" />
<!-- New -->
<PackageReference Include="SQLitePCLRaw.provider.sqlite3" Version="3.x.x" />
<!-- or -->
<PackageReference Include="SQLitePCLRaw.provider.winsqlite3" Version="3.x.x" />
Then add explicit initialization before using SQLite:
// For sqlite3
static void Init()
{
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3());
}
// For winsqlite3
static void Init()
{
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_winsqlite3());
}
If using SQLitePCLRaw.bundle_e_sqlite3mc, replace the package reference with SQLite3MC.PCLRaw.bundle:
<!-- Old -->
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3mc" Version="2.x.x" />
<!-- New -->
<PackageReference Include="SQLite3MC.PCLRaw.bundle" Version="2.x.x" />
If using SQLitePCLRaw.bundle_green, switch to SQLitePCLRaw.bundle_e_sqlite3. Alternatively, use SQLitePCLRaw.config.e_sqlite3 paired with a separate native library package such as SourceGear.sqlite3, which allows updating the SQLite version independently:
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.x.x" />
If you only target iOS and want to use the system SQLite library, reference the provider directly and initialize it explicitly:
<PackageReference Include="SQLitePCLRaw.Core" Version="3.x.x" />
<PackageReference Include="SQLitePCLRaw.provider.sqlite3" Version="3.x.x" />
static void Init()
{
SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3());
}
For more details, see SQLite encryption options for use with SQLitePCLRaw and SQLitePCLRaw 3.0 Release Notes.
Low-impact changes
SQLite no longer supports UWP and classic Xamarin
Old behavior
Previously, SQLitePCLRaw.bundle_e_sqlite3 included native SQLite builds for Universal Windows Platform (UWP) and classic Xamarin (Xamarin.iOS, Xamarin.Android, and Xamarin.Mac) targets.
New behavior
Starting with SQLitePCLRaw.bundle_e_sqlite3 2.1.12 (referenced by Microsoft.Data.Sqlite 11.0), native builds for UWP and classic Xamarin are no longer included. Applications targeting these platforms can no longer use the bundled native SQLite library.
Why
SQLite 3.53.0 (shipped by SQLitePCLRaw.bundle_e_sqlite3 2.1.12) no longer supports UWP and classic Xamarin. The SQLitePCLRaw maintainer dropped these builds in order to keep up with newer upstream SQLite releases.
Mitigations
Migrate UWP applications to the Windows App SDK and classic Xamarin applications to .NET MAUI, which are supported on modern .NET.
If you must remain on UWP or classic Xamarin, stay on an earlier version of SQLitePCLRaw.bundle_e_sqlite3 that still includes the native builds for these platforms.