From bd8a0dabe5588b4527b97e092c1e057df9fdbd18 Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Thu, 20 Aug 2026 07:34:15 +0200 Subject: [PATCH 1/5] Clarify SqlQuery support for unmapped types and nesting --- entity-framework/core/querying/sql-queries.md | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/entity-framework/core/querying/sql-queries.md b/entity-framework/core/querying/sql-queries.md index 422b69cf66..bbcde16eaa 100644 --- a/entity-framework/core/querying/sql-queries.md +++ b/entity-framework/core/querying/sql-queries.md @@ -248,8 +248,78 @@ var overAverageIds = await context.Database can be used with any scalar type supported by your database provider. If you'd like to use a type not supported by your database provider, you can use [pre-convention configuration](xref:core/modeling/bulk-configuration#pre-convention-configuration) to define a value conversion for it. + isn't limited to scalar types. You can also project each row of the result set into an arbitrary CLR type that isn't part of your EF model, as long as the type has a property for every column in the result set. See [Querying unmapped types](#querying-unmapped-types) below for more details. + allows for dynamic construction of SQL queries, just like does for entity types. +## Querying unmapped types + +> [!NOTE] +> Returning unmapped types from was introduced in EF Core 8.0. Support for unmapped types that contain nested [complex types](xref:core/modeling/complex-types) was added in a later release. + +In addition to scalar types, can populate instances of an arbitrary CLR type from the result set of a SQL query, without including that type in the EF model. The type used for the query results can contain common mapping constructs supported by EF Core, such as parameterized constructors and mapping attributes. For example, given the following type: + +```csharp +public class BlogPost +{ + public int Id { get; set; } + public string Title { get; set; } + public string Content { get; set; } + public DateOnly PublishedOn { get; set; } + public int BlogId { get; set; } +} +``` + +The type can be queried using in the same way as scalar types: + +```csharp +var start = new DateOnly(2022, 1, 1); +var end = new DateOnly(2023, 1, 1); +var posts = await context.Database + .SqlQuery($"SELECT * FROM Posts AS p WHERE p.PublishedOn >= {start} AND p.PublishedOn < {end}") + .ToListAsync(); +``` + +The type used must have a property for every value in the result set, but it doesn't need to match any table in the database - it can, for example, represent a subset of columns, or the result of a join across multiple tables. + +> [!NOTE] +> Unmapped types used in this way don't have keys defined and cannot have relationships to other types. Types with relationships must be mapped in the model. + +### Unmapped complex types + +The unmapped type returned by can also contain nested [complex types](xref:core/modeling/complex-types), allowing you to group several columns from the result set into a nested value object. For example, consider a `Address` complex type that is nested within a `Customer` result type: + +```csharp +public class Customer +{ + public int Id { get; set; } + public string Name { get; set; } + public Address Address { get; set; } +} + +public class Address +{ + public string Line1 { get; set; } + public string City { get; set; } + public string PostCode { get; set; } + public string Country { get; set; } +} +``` + +The nested complex type properties are populated from the result set using the same column-name conventions used when mapping complex types in the model, where each nested property maps to a column named with the complex property name and the nested property name joined by an underscore (for example, `Address_City`): + +```csharp +var customers = await context.Database + .SqlQuery( + $""" + SELECT [Id], [Name], [Address_Line1], [Address_City], [Address_PostCode], [Address_Country] + FROM [Customers] + """) + .ToListAsync(); +``` + +As with complex types in the model, the nested type doesn't have a key and cannot define relationships to other types. + ## Executing non-querying SQL In some scenarios, it may be necessary to execute SQL which does not return any data, typically for modifying data in the database or calling a stored procedure which doesn't return any result sets. This can be done via : From 1e27e0a6c1eb941d36c6e3e622e43824fd0d6adc Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Thu, 20 Aug 2026 07:51:40 +0200 Subject: [PATCH 2/5] fix grammar --- entity-framework/core/querying/sql-queries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/querying/sql-queries.md b/entity-framework/core/querying/sql-queries.md index bbcde16eaa..99b0166c84 100644 --- a/entity-framework/core/querying/sql-queries.md +++ b/entity-framework/core/querying/sql-queries.md @@ -287,7 +287,7 @@ The type used must have a property for every value in the result set, but it doe ### Unmapped complex types -The unmapped type returned by can also contain nested [complex types](xref:core/modeling/complex-types), allowing you to group several columns from the result set into a nested value object. For example, consider a `Address` complex type that is nested within a `Customer` result type: +The unmapped type returned by can also contain nested [complex types](xref:core/modeling/complex-types), allowing you to group several columns from the result set into a nested value object. For example, consider an `Address` complex type that is nested within a `Customer` result type: ```csharp public class Customer From cebfe55ea6a2a2b8197a99a184b40f04c9402072 Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Thu, 20 Aug 2026 08:09:21 +0200 Subject: [PATCH 3/5] address comments --- entity-framework/core/querying/sql-queries.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/entity-framework/core/querying/sql-queries.md b/entity-framework/core/querying/sql-queries.md index 99b0166c84..46a8dc161f 100644 --- a/entity-framework/core/querying/sql-queries.md +++ b/entity-framework/core/querying/sql-queries.md @@ -257,7 +257,7 @@ var overAverageIds = await context.Database > [!NOTE] > Returning unmapped types from was introduced in EF Core 8.0. Support for unmapped types that contain nested [complex types](xref:core/modeling/complex-types) was added in a later release. -In addition to scalar types, can populate instances of an arbitrary CLR type from the result set of a SQL query, without including that type in the EF model. The type used for the query results can contain common mapping constructs supported by EF Core, such as parameterized constructors and mapping attributes. For example, given the following type: +In addition to scalar types, can populate instances of a mappable CLR type from the result set of a SQL query, without including that type in the EF model. The type used for the query results can contain common mapping constructs supported by EF Core, such as parameterized constructors and mapping attributes. For example, given the following type: ```csharp public class BlogPost @@ -290,6 +290,7 @@ The type used must have a property for every value in the result set, but it doe The unmapped type returned by can also contain nested [complex types](xref:core/modeling/complex-types), allowing you to group several columns from the result set into a nested value object. For example, consider an `Address` complex type that is nested within a `Customer` result type: ```csharp +[ComplexType] public class Customer { public int Id { get; set; } From db075fe3ab7ec54aba1152123c26fd593a6b557f Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Thu, 20 Aug 2026 08:18:57 +0200 Subject: [PATCH 4/5] Fix comments --- entity-framework/core/querying/sql-queries.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/entity-framework/core/querying/sql-queries.md b/entity-framework/core/querying/sql-queries.md index 46a8dc161f..33ce4838b6 100644 --- a/entity-framework/core/querying/sql-queries.md +++ b/entity-framework/core/querying/sql-queries.md @@ -257,7 +257,7 @@ var overAverageIds = await context.Database > [!NOTE] > Returning unmapped types from was introduced in EF Core 8.0. Support for unmapped types that contain nested [complex types](xref:core/modeling/complex-types) was added in a later release. -In addition to scalar types, can populate instances of a mappable CLR type from the result set of a SQL query, without including that type in the EF model. The type used for the query results can contain common mapping constructs supported by EF Core, such as parameterized constructors and mapping attributes. For example, given the following type: +In addition to scalar types, can populate instances of a mappable CLR type from the result set of a SQL query, without including that type in the EF model. The type used for the query results can contain common mapping constructs supported by EF Core, such as parameterized constructors and mapping attributes. The type used must have a property for every value in the result set, but do not need to match any table in the database. For example, given the following type: ```csharp public class BlogPost @@ -290,7 +290,6 @@ The type used must have a property for every value in the result set, but it doe The unmapped type returned by can also contain nested [complex types](xref:core/modeling/complex-types), allowing you to group several columns from the result set into a nested value object. For example, consider an `Address` complex type that is nested within a `Customer` result type: ```csharp -[ComplexType] public class Customer { public int Id { get; set; } @@ -298,6 +297,7 @@ public class Customer public Address Address { get; set; } } +[ComplexType] public class Address { public string Line1 { get; set; } From f792bac26f41183278b57092c7a94493956e0e10 Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Thu, 20 Aug 2026 08:23:33 +0200 Subject: [PATCH 5/5] Grammar --- entity-framework/core/querying/sql-queries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entity-framework/core/querying/sql-queries.md b/entity-framework/core/querying/sql-queries.md index 33ce4838b6..027614066e 100644 --- a/entity-framework/core/querying/sql-queries.md +++ b/entity-framework/core/querying/sql-queries.md @@ -257,7 +257,7 @@ var overAverageIds = await context.Database > [!NOTE] > Returning unmapped types from was introduced in EF Core 8.0. Support for unmapped types that contain nested [complex types](xref:core/modeling/complex-types) was added in a later release. -In addition to scalar types, can populate instances of a mappable CLR type from the result set of a SQL query, without including that type in the EF model. The type used for the query results can contain common mapping constructs supported by EF Core, such as parameterized constructors and mapping attributes. The type used must have a property for every value in the result set, but do not need to match any table in the database. For example, given the following type: +In addition to scalar types, can populate instances of a mappable CLR type from the result set of a SQL query, without including that type in the EF model. The type used for the query results can contain common mapping constructs supported by EF Core, such as parameterized constructors and mapping attributes. The type used must have a property for every value in the result set, but does not need to match any table in the database. For example, given the following type: ```csharp public class BlogPost