Skip to content

Commit bf71bd0

Browse files
committed
What's new notes on complex types
Part of #4413
1 parent a0aaace commit bf71bd0

File tree

1 file changed

+118
-1
lines changed
  • entity-framework/core/what-is-new/ef-core-10.0

1 file changed

+118
-1
lines changed

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

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ EF10 is available as a preview. See [.NET 10 release notes](https://github.com/d
1717
1818
EF10 requires the .NET 10 SDK to build and requires the .NET 10 runtime to run. EF10 will not run on earlier .NET versions, and will not run on .NET Framework.
1919

20-
<a name="cosmos"></a>
20+
<a name="sql-server"></a>
2121

2222
## Azure SQL and SQL Server
2323

24+
<a name="sql-server-vector-search"></a>
25+
2426
### Vector search support
2527

2628
EF 10 brings full support for the recently-introduced [vector data type](/sql/t-sql/data-types/vector-data-type) and its supporting [`VECTOR_DISTANCE()`](/sql/t-sql/functions/vector-distance-transact-sql) function, available on Azure SQL Database and on SQL Server 2025. The vector data type allows storing *embeddings*, which are representation of meaning that can be efficiently searched over for similarity, powering AI workloads such as semantic search and retrieval-augmented generation (RAG).
@@ -63,6 +65,8 @@ var topSimilarBlogs = context.Blogs
6365

6466
For more information on vector search, [see the documentation](xref:core/providers/sql-server/vector-search).
6567

68+
<a name="sql-server-json-type"></a>
69+
6670
### JSON type support
6771

6872
EF 10 also fully supports the new [json data type](/sql/t-sql/data-types/json-data-type), also available on Azure SQL Database and on SQL Server 2025. While SQL Server has included JSON functionality for several versions, the data itself was stored in plain textual columns in the database; the new data type provides significant efficiency improvements and a safer way to store and interact with JSON.
@@ -148,6 +152,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
148152
> [!NOTE]
149153
> If you have existing migrations, the next migration you add will rename every single default constraint in your model.
150154
155+
<a name="cosmos"></a>
156+
151157
## Azure Cosmos DB for NoSQL
152158

153159
<a name="full-text-search-support"></a>
@@ -224,6 +230,117 @@ In previous versions of EF Core, evolving the model when using Azure Cosmos DB w
224230

225231
In EF 10 we improved this experience - EF will now materialize a default value for a required property, if no data is present for it in the document, rather than throw.
226232

233+
<a name="complex-types"></a>
234+
235+
## Complex types
236+
237+
Complex types are used to model types which are contained within your entity types and have no identity of their own; while entity types are (usually) mapped to a database table, complex types can be mapped to columns in their container table ("table splitting"), or to a single JSON column. Complex types introduce document modeling techniques, which can bring substantial performance benefits as traditional JOINs are avoided, and can make your database modeling much simpler and more natural.
238+
239+
### Table splitting
240+
241+
For example, the following maps a customer's addresses as complex types:
242+
243+
```c#
244+
modelBuilder.Entity<Customer>(b =>
245+
{
246+
b.ComplexProperty(c => c.ShippingAddress);
247+
b.ComplexProperty(c => c.BillingAddress);
248+
});
249+
```
250+
251+
On relational database, this causes the addresses to be mapped to additional columns in the main `Customers` table:
252+
253+
```sql
254+
CREATE TABLE [Customers] (
255+
[Id] int NOT NULL IDENTITY,
256+
[Name] nvarchar(max) NOT NULL,
257+
[BillingAddress_City] nvarchar(max) NOT NULL,
258+
[BillingAddress_PostalCode] nvarchar(max) NOT NULL,
259+
[BillingAddress_Street] nvarchar(max) NOT NULL,
260+
[BillingAddress_StreetNumber] int NOT NULL,
261+
[ShippingAddress_City] nvarchar(max) NOT NULL,
262+
[ShippingAddress_PostalCode] nvarchar(max) NOT NULL,
263+
[ShippingAddress_Street] nvarchar(max) NOT NULL,
264+
[ShippingAddress_StreetNumber] int NOT NULL,
265+
CONSTRAINT [PK_Customers] PRIMARY KEY ([Id])
266+
);
267+
```
268+
269+
Note the difference with the default, traditional relational behavior of mapping the addresses to a separate table and using a foreign key to represent the customer/address relationship.
270+
271+
While the above was already possible since EF 8, EF 10 adds support for **optional** types:
272+
273+
```c#
274+
public class Customer
275+
{
276+
...
277+
278+
public Address ShippingAddress { get; set; }
279+
public Address? BillingAddress { get; set; }
280+
}
281+
```
282+
283+
Note that optional complex types currently require at least one required property to be defined on the complex type.
284+
285+
### JSON
286+
287+
EF 10 now allows mapping complex types to JSON:
288+
289+
```c#
290+
modelBuilder.Entity<Customer>(b =>
291+
{
292+
b.ComplexProperty(c => c.ShippingAddress, c => c.ToJson());
293+
b.ComplexProperty(c => c.BillingAddress, c => c.ToJson());
294+
});
295+
```
296+
297+
This causes EF to map each Address to a single JSON column in the customer table. When using the new SQL Server 2025 JSON column ([see above](#sql-server-json-type)), this causes the following table to be created:
298+
299+
```sql
300+
CREATE TABLE [Customers] (
301+
[Id] int NOT NULL IDENTITY,
302+
[Name] nvarchar(max) NOT NULL,
303+
[ShippingAddress] json NOT NULL,
304+
[BillingAddress] json NOT NULL NULL,
305+
CONSTRAINT [PK_Customers] PRIMARY KEY ([Id])
306+
);
307+
```
308+
309+
Unlike table splitting, JSON mapping allows collections within the mapped type. You can query and update properties inside your JSON documents just like any other non-JSON property, and perform efficient bulk updating on them via `ExecuteUpdateAsync` ([see release note](#execute-update-json)).
310+
311+
### Struct support
312+
313+
Complex types also supports mapping .NET structs instead of classes:
314+
315+
```c#
316+
public struct Address
317+
{
318+
public required string Street { get; set; }
319+
public required string City { get; set; }
320+
public required string ZipCode { get; set; }
321+
}
322+
```
323+
324+
This aligns well with complex types not having an identity of their own, and only being found within entity types which have an identity. However, collections of structs currently aren't currently supported.
325+
326+
### Complex and owned entity types
327+
328+
Both table splitting and JSON mapping have been supported before EF 10 via owned entity modeling. However, this modeling created quite a few issues stemming from the fact that owned entity types are entity types, and therefore still operate with reference semantics and an identity behind the scenes.
329+
330+
For example, trying to assign a customer's billing address to be the same as their shipping address fails with owned entity types, since the same entity type can't be referenced more than once:
331+
332+
```c#
333+
var customer = await context.Customers.SingleAsync(c => c.Id == someId);
334+
customer.BillingAddress = customer.ShippingAddress;
335+
await context.SaveChangesAsync(); // ERROR
336+
```
337+
338+
In contrast, since complex types have value semantics, assigning them simply copies their properties over, as expected. For the same reasons, bulk assignment of owned entity types is not supported, whereas complex types fully support `ExecuteUpdateAsync` in EF 10 ([see release note](#execute-update-json)).
339+
340+
Similarly, comparing a customer's shipping and billing addresses in LINQ queries does not work as expected, since entity types are compared by their identities; complex types, on the other hand, are compared by their contents, producing the expected result.
341+
342+
These issues - as well as various others - make complex types the better choice for modeling JSON and table splitting, and users already using owned entity types for these are advised to switch to complex types.
343+
227344
<a name="linq-and-sql-translation"></a>
228345

229346
## LINQ and SQL translation

0 commit comments

Comments
 (0)