dotConnect providers now support Entity Framework Core 11 on .NET 11, introducing new capabilities for working with JSON data, primitive collections, and LINQ queries. You can update individual properties in JSON documents, query and index JSON paths, filter data using primitive collections, and use FULL JOIN and ordered string aggregates. Your existing models keep working: the packages are the same, now with EF Core 11 builds.
For a complete list of updates and improvements, see the dotConnect 2026.1 release announcement.
.NET 11 and Entity Framework Core 11 are out, and dotConnect supports both from day one. EF Core 11 is the release where JSON columns and complex types become something you can query, update and index like ordinary columns. dotConnect translates these operations into the native SQL of your database, whether that is Oracle, MySQL, PostgreSQL, SQLite or DB2.
What’s inside
- Supported providers and versions
- JSON columns and complex types
- Primitive collections
- New LINQ translations
- Migrations and tooling
- Good news for EF Core 7–10 users
- Bug fixes
Supported providers and versions
Entity Framework Core 11 is supported in the following dotConnect providers:
The EF Core 11 build requires .NET 11. It ships in the same NuGet package as the builds for earlier EF Core versions: the version number of the EF Core 11 build ends with .11, just as the EF Core 10 build ends with .10.
<PackageReference Include="Devart.Data.Oracle.EFCore" Version="11.3.248.11" />
Nothing changes in the way you configure the context:
optionsBuilder.UseOracle(connectionString);
All dotConnect providers are also compatible with .NET 11.
JSON columns and complex types
In EF Core 11, most of the changes are about JSON, and the database provider carries most of the weight. Each JSON member path must be translated into database-specific JSON functions. The examples in this section use one model: a customer with contact information stored in a single JSON column.
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public ContactInfo Contact { get; set; } // stored as one JSON column
public List<string> Tags { get; set; } // a primitive collection
}
public class ContactInfo
{
public string Email { get; set; }
public Address Address { get; set; }
public List<Phone> Phones { get; set; }
}
modelBuilder.Entity<Customer>(b =>
{
b.ComplexProperty(c => c.Contact, cb =>
{
cb.ToJson();
cb.Property(x => x.Email).HasMaxLength(100);
cb.ComplexProperty(x => x.Address);
cb.ComplexCollection(x => x.Phones);
});
b.PrimitiveCollection(c => c.Tags);
});
Partial updates of JSON columns
Before EF Core 11, changing one property inside a JSON document meant writing the whole document back. Now, for owned entity types mapped to JSON, the UPDATE statement changes only the member that has changed. Let’s map Contact as an owned type this time:
modelBuilder.Entity<Customer>().OwnsOne(c => c.Contact, b =>
{
b.ToJson();
b.OwnsOne(x => x.Address);
b.OwnsMany(x => x.Phones);
});
var customer = context.Customers.Single(c => c.Id == 1);
customer.Contact.Address.City = "Berlin";
context.SaveChanges();
dotConnect generates the native partial-update function of each database:
-- Oracle 21c and later
UPDATE "Customers" SET "Contact" = TO_NCLOB(JSON_TRANSFORM("Contact", SET '$."Address"."City"' = :p0 FORMAT JSON RETURNING CLOB))
WHERE "Id" = :p1
-- PostgreSQL
UPDATE "Customers" SET "Contact" = jsonb_set(CAST("Contact" AS jsonb), '{"Address","City"}', CAST($1 AS jsonb))
WHERE "Id" = $2
-- MySQL 5.7.8 and later
UPDATE Customers SET Contact = JSON_SET(Contact, '$.Address.City', CAST(:p0 AS JSON))
WHERE Id = :p1
SQLite uses json_set. Oracle 18c and 19c use JSON_MERGEPATCH, and newer 19c release updates use JSON_TRANSFORM as well. With MongoDB, only the changed field is updated.
Less data goes to the server, and members of the document that are not mapped in your model are preserved. Change one property — send one property.
For a complex type mapped to JSON (ComplexProperty().ToJson()), EF Core 11 itself always writes the whole document when any of its members changes. DB2 and older servers (PostgreSQL 9.4, MySQL 5.7, Oracle 12.2) have no partial-update function, so with them the provider writes the whole document for owned types too.
Queries by JSON path
You can filter, sort and project by members of a JSON document, including array elements, as if they were ordinary columns:
var berliners = context.Customers
.Where(c => c.Contact.Address.City == "Berlin")
.OrderBy(c => c.Contact.Email)
.Select(c => new { c.Name, FirstPhone = c.Contact.Phones[0].Number })
.ToList();
-- Oracle
SELECT "c"."Name", JSON_VALUE("c"."Contact", '$."Phones"[0]."Number"') "FirstPhone"
FROM "Customers" "c"
WHERE (JSON_VALUE("c"."Contact", '$."Address"."City"')) = N'Berlin'
ORDER BY JSON_VALUE("c"."Contact", '$."Email"')
-- PostgreSQL
SELECT c."Name", (c."Contact" #>> '{"Phones","0","Number"}') AS "FirstPhone"
FROM "Customers" AS c
WHERE ((c."Contact" #>> '{"Address","City"}')) = 'Berlin'
ORDER BY (c."Contact" ->> 'Email')
-- MySQL
SELECT c.Name, JSON_UNQUOTE(NULLIF(JSON_EXTRACT(c.Contact, '$.Phones[0].Number'), CAST('null' AS JSON))) AS FirstPhone
FROM Customers AS c
WHERE (JSON_UNQUOTE(NULLIF(JSON_EXTRACT(c.Contact, '$.Address.City'), CAST('null' AS JSON)))) = 'Berlin'
ORDER BY JSON_UNQUOTE(NULLIF(JSON_EXTRACT(c.Contact, '$.Email'), CAST('null' AS JSON)))
In MySQL, NULLIF(..., CAST('null' AS JSON)) turns a JSON null into SQL NULL, so City == null finds such documents too. SQLite uses json_extract. Values of other types are converted to the type of the property, for example, with RETURNING NUMBER in Oracle or CAST(... AS int4) in PostgreSQL. Reload() and GetDatabaseValues() work with JSON-mapped complex and owned types too.
The EF.Functions.JsonPathExists() method now accepts complex and owned types mapped to JSON. It is supported by Oracle, MySQL, PostgreSQL, SQLite and MongoDB.
For PostgreSQL and MySQL, dotConnect also adds the EF.Functions.JsonContains() method. It checks whether a JSON document contains a given JSON value, and the document can be a string column with JSON text or a complex or owned type mapped to JSON. The method is translated to @> in PostgreSQL and JSON_CONTAINS in MySQL. An optional path argument checks only the value at that path (PostgreSQL 12 and later).
JSON indexes in migrations
If you filter by a JSON path, you can index it. Define the index in the model, and the migration creates it:
modelBuilder.Entity<Customer>().HasIndex("Contact.Email").IsUnique();
modelBuilder.Entity<Customer>().HasIndex("Contact.Address.City");
-- Oracle
CREATE UNIQUE INDEX "IX_Customers_Contact_Email" ON "Customers" (JSON_VALUE("Contact", '$.Email' RETURNING VARCHAR2(100)))
CREATE INDEX "IX_Customers_Contact_Address_City" ON "Customers" (JSON_VALUE("Contact", '$.Address.City' RETURNING VARCHAR2(100)))
-- PostgreSQL
CREATE UNIQUE INDEX "IX_Customers_Contact_Email" ON "Customers" (("Contact" ->> 'Email'))
CREATE INDEX "IX_Customers_Contact_Address_City" ON "Customers" (("Contact" #>> '{Address,City}'))
-- MySQL 8.0.13 and later
CREATE UNIQUE INDEX IX_Customers_Contact_Email ON Customers
((CAST(JSON_UNQUOTE(NULLIF(JSON_EXTRACT(Contact, '$.Email'), CAST('null' AS JSON))) AS CHAR(100))))
The length in Oracle’s RETURNING VARCHAR2(n) and in MySQL’s CHAR(n) comes from HasMaxLength() of the property (without it, Oracle uses 4000 and MySQL uses 255). Numeric members are indexed as numbers. In MySQL, a unique JSON index accepts several documents with a null value. SQLite indexes json_extract, and DB2 for LUW 11.1 and later indexes JSON_VALUE. JSON indexes are not supported for MariaDB. PostgreSQL 12 and later can also index all elements of an array (Contact.Phones[].Number) with a GIN index. For MongoDB, the provider creates a native MongoDB index on the field path, and a multikey index for arrays.
Complex types grow up
EF Core 11 removes most of the remaining limitations of complex types, and dotConnect supports all of them:
- Complex types and JSON columns on entity types with TPT and TPC inheritance.
- Keys and indexes on complex type properties in migrations.
- Property chains such as
Property(e => e.Details.Description), comparison of nested complex types, andExecuteUpdate()that assigns a whole complex value.
modelBuilder.Entity<Order>(b =>
{
b.ComplexProperty(o => o.ShipTo).IsRequired();
b.HasIndex(o => o.ShipTo.City);
});
-- Oracle
CREATE INDEX "IX_Orders_ShipTo_City" ON "Orders" ("ShipTo_City")
If you design your models visually, Entity Developer now maps complex types with ComplexProperty for EF Core 11 as well.
Primitive collections
Collections of simple values, such as tags, IDs, and roles, are common. EF Core 11 stores them as JSON arrays, and dotConnect now translates LINQ operators over them to SQL. Map the property with PrimitiveCollection(), as Tags in the model above. Queries that used to fail with “could not be translated” now run on the server:
var vips = context.Customers
.Where(c => c.Tags.Contains("vip"))
.Select(c => new { c.Name, TagCount = c.Tags.Count() })
.ToList();
Contains() uses the native JSON functions of each database, and Count() goes through a JSON table:
-- Oracle 12.2 and later
SELECT "c"."Name", (
SELECT COUNT(*)
FROM JSON_TABLE("c"."Tags", '$[*]' COLUMNS ("key" FOR ORDINALITY, "value" VARCHAR2(4000) PATH '$')) "t") "TagCount"
FROM "Customers" "c"
WHERE (((CASE WHEN JSON_EXISTS("c"."Tags", '$[*]?(@ == $v)' PASSING TO_CHAR(N'vip') AS "v") THEN 1 ELSE 0 END = 1) AND "c"."Tags" IS NOT NULL))
-- PostgreSQL (the WHERE clause)
WHERE (((CAST(c."Tags" AS jsonb) @> jsonb_build_array(CAST('vip' AS text))) AND c."Tags" IS NOT NULL))
-- MySQL 8.0.17 and later (the WHERE clause)
WHERE ((('vip' MEMBER OF (c.Tags)) AND c.Tags IS NOT NULL))
Older MySQL versions use JSON_CONTAINS, and SQLite and MongoDB use json_each. Other operators such as Count(), Any(), FirstOrDefault() and ElementAt() go through a JSON table: JSON_TABLE in Oracle 12.2+, jsonb_array_elements_text in PostgreSQL, JSON_TABLE in MySQL 8.0.4+ and MariaDB 10.6+, and json_each in SQLite.
A collection property, such as List<string>, configured with Property() is now stored as a JSON string too, as EF Core 11 requires.
New LINQ translations
EF Core 11 expands LINQ query capabilities, and dotConnect adds new database-specific translations to support them. These enhancements cover joins, string aggregation, date and time operations, and more.
FULL JOIN
.NET 11 adds the FullJoin() LINQ operator, and EF Core 11 can translate it. dotConnect turns it into FULL JOIN:
var report = context.Blogs
.FullJoin(context.Posts,
b => b.Id, p => p.BlogId,
(b, p) => new { Blog = b == null ? null : b.Name, Post = p == null ? null : p.Title })
.ToList();
-- Oracle
SELECT "b"."Name" "Blog", "p"."Title" "Post"
FROM "Blogs" "b"
FULL JOIN "Posts" "p" ON "b"."Id" = "p"."BlogId"
The result has blogs without posts and posts without a blog in one query. FULL JOIN is supported for Oracle, PostgreSQL, DB2, SQLite 3.39 and later, and MongoDB.
Ordered string aggregates
string.Join() and string.Concat() over a group, with OrderBy() inside, are now translated to the string aggregate function of the database. The database returns one row per group, with values in the order you specified:
var titles = context.Posts
.GroupBy(p => p.BlogId)
.Select(g => new
{
BlogId = g.Key,
Titles = string.Join(", ", g.OrderBy(p => p.Title).Select(p => p.Title))
})
.ToList();
-- Oracle
SELECT "p"."BlogId", (SUBSTR(LISTAGG((N', ' || "p"."Title")) WITHIN GROUP (ORDER BY "p"."Title"), LENGTH(N', ') + 1)) "Titles"
FROM "Posts" "p"
GROUP BY "p"."BlogId"
-- PostgreSQL
SELECT p."BlogId", COALESCE(string_agg(COALESCE(p."Title", ''), ', ' ORDER BY p."Title"), '') AS "Titles"
FROM "Posts" AS p
GROUP BY p."BlogId"
-- MySQL
SELECT p.BlogId, COALESCE(GROUP_CONCAT(COALESCE(p.Title, '') ORDER BY p.Title SEPARATOR ', '), '') AS Titles
FROM Posts AS p
GROUP BY p.BlogId
The Title column must be a string type that the aggregate accepts, so give it a length with HasMaxLength(): Oracle cannot aggregate or sort NCLOB values. Oracle treats an empty string as NULL and LISTAGG skips NULL values, so the provider puts the separator before each element and cuts the first one off. This way empty elements are not lost. In MySQL, SEPARATOR accepts only a literal, so a separator from a variable makes EF Core build the string on the client. DB2 also uses LISTAGG ... WITHIN GROUP (ORDER BY ...), and SQLite uses group_concat (ordering requires SQLite 3.44 or later).
EF.Functions.DateTrunc
dotConnect adds the EF.Functions.DateTrunc() method to each provider. It truncates a date and time value to the year, quarter, month, day, hour or minute, which makes it easy to group data by period:
var ordersPerMonth = context.Orders
.GroupBy(o => EF.Functions.DateTrunc("month", o.CreatedAt))
.Select(g => new { Month = g.Key, Count = g.Count() })
.ToList();
| Database | SQL |
|---|---|
| Oracle | TRUNC("o"."CreatedAt", 'MM') |
| PostgreSQL | date_trunc('month', o."CreatedAt") |
| MySQL | CAST(DATE_FORMAT(o.CreatedAt, '%Y-%m-01') AS DATETIME) |
| SQLite | strftime(...) |
| DB2 | TRUNC_TIMESTAMP(..., ...) |
DateTimeOffset in Oracle
Oracle’s TIMESTAMP WITH TIME ZONE keeps the time zone offset of each value, so dotConnect for Oracle translates the DateTime, UtcDateTime and LocalDateTime members of DateTimeOffset, the ToOffset() method, and the DateTimeOffset constructor.
var since = new DateTime(2026, 1, 1);
var upcoming = context.Events
.Where(e => e.StartsAt.UtcDateTime >= since)
.ToList();
-- Oracle
SELECT "e"."Id", "e"."Name", "e"."StartsAt"
FROM "Events" "e"
WHERE SYS_EXTRACT_UTC("e"."StartsAt") >= :since
dotConnect for PostgreSQL translates these members too, except ToOffset(). Since timestamptz stores values in UTC, the time and the offset are those of the session time zone.
Also translated
MaxBy()andMinBy(), and the newGroupByshapes of EF Core 11: the whole entity of a group, and navigations of the top row of a group.EF.Functionsmethods whose arguments are only variables and constants. They are now translated to SQL instead of failing with the “can only be invoked from LINQ to Entities” error. This also works in EF Core 8, 9 and 10.
Migrations and tooling
ExcludeForeignKeyFromMigrations(). Sometimes you need a relationship in the model but no foreign key constraint in the database, for example with legacy databases or bulk data loads. EF Core 11 lets you say exactly that:
modelBuilder.Entity<Post>()
.HasOne(p => p.Blog).WithMany(b => b.Posts)
.HasForeignKey(p => p.BlogId)
.ExcludeForeignKeyFromMigrations();
The migration creates no constraint, but the index on the foreign key column stays. Rows that reference a nonexistent blog can be inserted, and FULL JOIN in the example above finds them.
New migration tools. dotConnect supports dotnet ef database update --add, which creates a migration and applies it in one step. It also supports the new MigrationsNotFound and PendingModelChanges errors, and the ID of the latest migration in the model snapshot.
Dropping the database. dotnet ef database drop now drops a non-empty migration history table. For MySQL and DB2, this table was not dropped before.
Batching for DB2 for LUW. SaveChanges now sends several commands in one BEGIN ATOMIC ... END block, and optimistic concurrency checks keep working.
Limitations. Some database features are not available everywhere, and dotConnect reports a clear error instead of a server syntax error. MySQL and MariaDB do not support FULL JOIN. DB2 does not support queries by JSON path or Contains() over primitive collections. Idempotent migration scripts (dotnet ef migrations script --idempotent) are not supported for MySQL, SQLite and DB2.
Good news for EF Core 7–10 users
Not ready to move to EF Core 11 yet? The new builds bring improvements for earlier EF Core versions too:
- Primitive collections in EF Core 8, 9 and 10. Properties such as
List<int>andstring[]configured withPrimitiveCollection()are now stored as JSON arrays in Oracle, MySQL, PostgreSQL, SQLite and DB2. Before, the model could not be built. Queries over them still require EF Core 11. - Check constraints in EF Core 7 and later. Check constraints defined with
HasCheckConstraint()are now created with the table and added or dropped by migrations. When SQLite rebuilds a table, the check constraints are kept. - NetTopologySuite. The Oracle, MySQL, PostgreSQL and SQLite providers now support more spatial members:
Dimension,SRID,NumInteriorRings,IsWithinDistance(),Covers()andCoveredBy().GetPointN(),GetGeometryN()andGetInteriorRingN()now count from one, and spatial functions return proper geometry results. This works in all EF Core versions. - Inline collections and APPLY operations in LINQ queries: Oracle and MySQL in EF Core 8 and later, DB2 in EF Core 10.
- DB2.
Skip()is now supported on DB2 versions before 11.1, and so are correlated subqueries withTake()(EF Core 10).
Bug fixes
This release also fixes a number of issues in earlier EF Core versions. The highlights:
- JSON and model building (EF Core 7–10). These errors are fixed: a NullReferenceException for owned types mapped to JSON and an InvalidCastException for complex properties. Changing one property of an owned JSON type no longer overwrites the whole document with that value.
- SQL generation. String concatenation is no longer generated as numeric addition (MySQL, SQLite, DB2). The
%operator works on Oracle and DB2. Casts todoublekeep the fractional part on MySQL.DateTimeOffsetdate parts no longer return NULL on SQLite. Split queries no longer cause the “Commands out of sync” error on MySQL. OUTER APPLY and CROSS APPLY are fixed for PostgreSQL, MySQL and DB2, andTake()is fixed for DB2. - Spatial data. Geometry properties on MySQL no longer fail with the “No coercion operator is defined” error, and several geometry issues in EF Core 3.1 are fixed for Oracle and PostgreSQL.
- Saving changes on DB2. Saving several entities in one batch and inserting entities of a derived type in TPT inheritance no longer fail.
- Migrations and scaffolding. Scripts from
dotnet ef migrations scriptnow have statement separators for Oracle, DB2 and SQLite, so they run as generated.AddPrimaryKey()respects the table schema. Scaffolding now generates the correct primary keys, unique constraints, delete behavior and indexes for PostgreSQL, MySQL, Oracle and SQLite. - Oracle and EF Core 3.1. A NullReferenceException that affected any model is fixed, along with ORA-00907 and ORA-00920 errors.
- Entity Framework 6. Spatial functions and decimal-to-double casts are fixed for MySQL, Oracle and PostgreSQL.
See the revision history of each provider for the full list.
Get started
EF Core 11 support is now available across dotConnect providers for Oracle, MySQL, PostgreSQL, SQLite, DB2, MongoDB, Google BigQuery, and supported cloud services. To get started, update your provider’s NuGet package or download the latest installer. You can continue using your existing models while taking advantage of the new EF Core 11 features.
Have you tried EF Core 11 with dotConnect? We’d love to hear about your experience. Share your feedback or questions with our support team.

