DTO Projections with Constructors
This recipe shows how to use [Expressive] constructors to project database rows directly into DTOs inside your LINQ queries -- with no boilerplate Select expressions and full SQL translation.
The Problem
Projecting entities into DTOs usually requires writing a Select expression that repeats the mapping logic:
// Repetitive -- mapping duplicated in every query
var customers = dbContext.Customers
.Select(c => new CustomerDto
{
Id = c.Id,
FullName = $"{c.FirstName} {c.LastName}",
IsActive = c.IsActive,
OrderCount = c.Orders.Count()
})
.ToList();If the mapping changes you must update every Select that uses it.
The Solution: [Expressive] Constructor
Mark a constructor with [Expressive] and call it directly in your query. The source generator emits a MemberInit expression that EF Core translates to SQL:
db
.Customers
.Where(c => c.Country != null)
.Select(c => new CustomerDto(c))
// Setup
public class CustomerDto
{
public int Id { get; set; }
public string Name { get; set; } = "";
public string? Country { get; set; }
public int OrderCount { get; set; }
public CustomerDto() { }
[Expressive]
public CustomerDto(Customer c)
{
Id = c.Id;
Name = c.Name;
Country = c.Country;
OrderCount = c.Orders.Count();
}
}SELECT "c"."Id", "c"."Name", "c"."Country", (
SELECT COUNT(*)
FROM "Orders" AS "o"
WHERE "c"."Id" = "o"."CustomerId") AS "OrderCount"
FROM "Customers" AS "c"
WHERE "c"."Country" IS NOT NULLSELECT c."Id", c."Name", c."Country", (
SELECT count(*)::int
FROM "Orders" AS o
WHERE c."Id" = o."CustomerId") AS "OrderCount"
FROM "Customers" AS c
WHERE c."Country" IS NOT NULLSELECT [c].[Id], [c].[Name], [c].[Country], (
SELECT COUNT(*)
FROM [Orders] AS [o]
WHERE [c].[Id] = [o].[CustomerId]) AS [OrderCount]
FROM [Customers] AS [c]
WHERE [c].[Country] IS NOT NULLplayground.customers.Aggregate([
{
"$match" : {
"Country" : { "$ne" : null }
}
},
{
"$project" : {
"_id" : "$_id",
"Name" : "$Name",
"Country" : "$Country",
"OrderCount" : { "$size" : "$Orders" }
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_CustomerDto._ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Customer.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_CustomerDto
{
// [Expressive]
// public CustomerDto(Customer c)
// {
// Id = c.Id;
// Name = c.Name;
// Country = c.Country;
// OrderCount = c.Orders.Count();
// }
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, global::ExpressiveSharp.Docs.Playground.Snippet.CustomerDto>> _ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Customer_Expression()
{
var p_c = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer), "c");
var expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null));
var expr_1 = global::System.Linq.Expressions.Expression.Property(p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Id
var expr_2 = global::System.Linq.Expressions.Expression.Property(p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Name
var expr_3 = global::System.Linq.Expressions.Expression.Property(p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Country", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Country
var expr_5 = global::System.Linq.Expressions.Expression.Property(p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Orders", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Orders
var expr_4 = global::System.Linq.Expressions.Expression.Call(global::System.Linq.Enumerable.First(global::System.Linq.Enumerable.Where(typeof(global::System.Linq.Enumerable).GetMethods(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static), m => m.Name == "Count" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.IsGenericType && !m.GetParameters()[0].ParameterType.IsGenericParameter)).MakeGenericMethod(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order)), new global::System.Linq.Expressions.Expression[] { expr_5 });
var expr_6 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerDto).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_1);
var expr_7 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerDto).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_2);
var expr_8 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerDto).GetProperty("Country", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_3);
var expr_9 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerDto).GetProperty("OrderCount", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_4);
var expr_10 = global::System.Linq.Expressions.Expression.MemberInit(expr_0, expr_6, expr_7, expr_8, expr_9);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, global::ExpressiveSharp.Docs.Playground.Snippet.CustomerDto>>(expr_10, p_c);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_CustomerDto.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_CustomerDto { }
}
// === ExpressionRegistry.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static class ExpressionRegistry
{
private static Dictionary<nint, LambdaExpression> Build()
{
const BindingFlags allFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
var map = new Dictionary<nint, LambdaExpression>();
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerDto).GetConstructor(allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_CustomerDto", "_ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Customer_Expression");
return map;
}
private static volatile Dictionary<nint, LambdaExpression> _map = Build();
internal static void ResetMap() => _map = Build();
public static LambdaExpression TryGet(MemberInfo member)
{
var handle = member switch
{
MethodInfo m => (nint?)m.MethodHandle.Value,
PropertyInfo p => p.GetMethod?.MethodHandle.Value,
ConstructorInfo c => (nint?)c.MethodHandle.Value,
_ => null
};
return handle.HasValue && _map.TryGetValue(handle.Value, out var expr) ? expr : null;
}
private static void Register(Dictionary<nint, LambdaExpression> map, MethodBase m, string exprClass, string exprMethodName)
{
if (m is null) return;
var exprType = m.DeclaringType?.Assembly.GetType(exprClass) ?? typeof(ExpressionRegistry).Assembly.GetType(exprClass);
var exprMethod = exprType?.GetMethod(exprMethodName, BindingFlags.Static | BindingFlags.NonPublic);
if (exprMethod is null) return;
var expr = (LambdaExpression)exprMethod.Invoke(null, null)!;
// Apply declared transformers from the generated class (if any)
const string expressionSuffix = "_Expression";
if (exprMethodName.EndsWith(expressionSuffix, StringComparison.Ordinal))
{
var transformersSuffix = exprMethodName.Substring(0, exprMethodName.Length - expressionSuffix.Length) + "_Transformers";
var transformersMethod = exprType.GetMethod(transformersSuffix, BindingFlags.Static | BindingFlags.NonPublic);
if (transformersMethod?.Invoke(null, null) is global::ExpressiveSharp.IExpressionTreeTransformer[] transformers)
{
Expression transformed = expr;
foreach (var t in transformers) transformed = t.Transform(transformed);
if (transformed is LambdaExpression lambdaResult) expr = lambdaResult;
}
}
map[m.MethodHandle.Value] = expr;
}
}
}
// === PolyfillInterceptors_b1293e61.g.cs ===
// <auto-generated/>
#nullable disable
namespace ExpressiveSharp.Generated.Interceptors
{
internal static partial class PolyfillInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "G8FTZQB0uOILx9INpC1Ka6oBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.Playground.Snippet.CustomerDto> __Polyfill_Select_3e61_16_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, global::ExpressiveSharp.Docs.Playground.Snippet.CustomerDto> __func)
{
// Source: c => new CustomerDto(c)
var i3e6116c5_p_c = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer), "c");
var i3e6116c5_expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer) }, null), i3e6116c5_p_c); // new CustomerDto(c)
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, global::ExpressiveSharp.Docs.Playground.Snippet.CustomerDto>>(i3e6116c5_expr_0, i3e6116c5_p_c);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer>)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "G8FTZQB0uOILx9INpC1Ka4cBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer> __Polyfill_Where_3e61_15_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, bool> __func)
{
// Source: c => c.Country != null
var i3e6115c5_p_c = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer), "c");
var i3e6115c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Country", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Country
var i3e6115c5_expr_3 = global::System.Linq.Expressions.Expression.Constant(null, typeof(object)); // null
var i3e6115c5_expr_2 = global::System.Linq.Expressions.Expression.Convert(i3e6115c5_expr_3, typeof(string));
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.NotEqual, i3e6115c5_expr_1, i3e6115c5_expr_2);
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, bool>>(i3e6115c5_expr_0, i3e6115c5_p_c);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Where(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer>)source,
__lambda));
}
}
}
namespace System.Runtime.CompilerServices
{
[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : global::System.Attribute
{
public InterceptsLocationAttribute(int version, string data) { }
}
}db
.Customers
.Where(c => c.Country != null)
.Select(c => new CustomerDto(c))
// Setup
public class CustomerDto
{
public int Id { get; set; }
public string Name { get; set; } = "";
public string? Country { get; set; }
public int OrderCount { get; set; }
public CustomerDto() { }
[Expressive]
public CustomerDto(Customer c)
{
Id = c.Id;
Name = c.Name;
Country = c.Country;
OrderCount = c.Orders.Count();
}
}Generated SQL:
SELECT "c"."Id", "c"."Name", "c"."Country", (
SELECT COUNT(*)
FROM "Orders" AS "o"
WHERE "c"."Id" = "o"."CustomerId") AS "OrderCount"
FROM "Customers" AS "c"
WHERE "c"."Country" IS NOT NULLThe constructor body is inlined as SQL -- no data is fetched to memory for the projection.
Basic Constructor Projection: OrderSummaryDto
A straightforward example showing how constructor parameters map to SQL expressions:
db
.Orders
.Select(o => new OrderSummaryDto(o.Id, o.Status.ToString(), o.ItemCount()))
// Setup
public static class OrderExt
{
[Expressive]
public static int ItemCount(this Order o) => o.Items.Count();
}
public class OrderSummaryDto
{
public int Id { get; set; }
public string Description { get; set; } = "";
public int Items { get; set; }
public OrderSummaryDto() { }
[Expressive]
public OrderSummaryDto(int id, string description, int items)
{
Id = id;
Description = description;
Items = items;
}
}SELECT "o"."Id", CASE
WHEN "o"."Status" = 0 THEN 'Pending'
WHEN "o"."Status" = 1 THEN 'Paid'
WHEN "o"."Status" = 2 THEN 'Shipped'
WHEN "o"."Status" = 3 THEN 'Delivered'
WHEN "o"."Status" = 4 THEN 'Refunded'
END AS "Description", (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") AS "Items"
FROM "Orders" AS "o"SELECT o."Id", CASE
WHEN o."Status" = 0 THEN 'Pending'
WHEN o."Status" = 1 THEN 'Paid'
WHEN o."Status" = 2 THEN 'Shipped'
WHEN o."Status" = 3 THEN 'Delivered'
WHEN o."Status" = 4 THEN 'Refunded'
END AS "Description", (
SELECT count(*)::int
FROM "LineItems" AS l
WHERE o."Id" = l."OrderId") AS "Items"
FROM "Orders" AS oSELECT [o].[Id], CASE
WHEN [o].[Status] = 0 THEN N'Pending'
WHEN [o].[Status] = 1 THEN N'Paid'
WHEN [o].[Status] = 2 THEN N'Shipped'
WHEN [o].[Status] = 3 THEN N'Delivered'
WHEN [o].[Status] = 4 THEN N'Refunded'
END AS [Description], (
SELECT COUNT(*)
FROM [LineItems] AS [l]
WHERE [o].[Id] = [l].[OrderId]) AS [Items]
FROM [Orders] AS [o]playground.orders.Aggregate([
{
"$project" : {
"_id" : "$_id",
"Description" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 0]
},
"then" : "Pending",
"else" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 1]
},
"then" : "Paid",
"else" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 2]
},
"then" : "Shipped",
"else" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 3]
},
"then" : "Delivered",
"else" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 4]
},
"then" : "Refunded",
"else" : null
}
}
}
}
}
}
}
}
}
},
"Items" : { "$size" : "$Items" }
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.ItemCount_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt
{
// [Expressive]
// public static int ItemCount(this Order o) => o.Items.Count();
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, int>> ItemCount_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression()
{
var p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var expr_1 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Items", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Items
var expr_0 = global::System.Linq.Expressions.Expression.Call(global::System.Linq.Enumerable.First(global::System.Linq.Enumerable.Where(typeof(global::System.Linq.Enumerable).GetMethods(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static), m => m.Name == "Count" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.IsGenericType && !m.GetParameters()[0].ParameterType.IsGenericParameter)).MakeGenericMethod(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem)), new global::System.Linq.Expressions.Expression[] { expr_1 });
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, int>>(expr_0, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderSummaryDto._ctor_P0_int_P1_string_P2_int.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderSummaryDto
{
// [Expressive]
// public OrderSummaryDto(int id, string description, int items)
// {
// Id = id;
// Description = description;
// Items = items;
// }
static global::System.Linq.Expressions.Expression<global::System.Func<int, string, int, global::ExpressiveSharp.Docs.Playground.Snippet.OrderSummaryDto>> _ctor_P0_int_P1_string_P2_int_Expression()
{
var p_id = global::System.Linq.Expressions.Expression.Parameter(typeof(int), "id");
var p_description = global::System.Linq.Expressions.Expression.Parameter(typeof(string), "description");
var p_items = global::System.Linq.Expressions.Expression.Parameter(typeof(int), "items");
var expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderSummaryDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null));
var expr_1 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderSummaryDto).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), p_id);
var expr_2 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderSummaryDto).GetProperty("Description", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), p_description);
var expr_3 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderSummaryDto).GetProperty("Items", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), p_items);
var expr_4 = global::System.Linq.Expressions.Expression.MemberInit(expr_0, expr_1, expr_2, expr_3);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<int, string, int, global::ExpressiveSharp.Docs.Playground.Snippet.OrderSummaryDto>>(expr_4, p_id, p_description, p_items);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt { }
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderSummaryDto.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderSummaryDto { }
}
// === ExpressionRegistry.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static class ExpressionRegistry
{
private static Dictionary<nint, LambdaExpression> Build()
{
const BindingFlags allFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
var map = new Dictionary<nint, LambdaExpression>();
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("ItemCount", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderExt", "ItemCount_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderSummaryDto).GetConstructor(allFlags, null, new global::System.Type[] { typeof(int), typeof(string), typeof(int) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderSummaryDto", "_ctor_P0_int_P1_string_P2_int_Expression");
return map;
}
private static volatile Dictionary<nint, LambdaExpression> _map = Build();
internal static void ResetMap() => _map = Build();
public static LambdaExpression TryGet(MemberInfo member)
{
var handle = member switch
{
MethodInfo m => (nint?)m.MethodHandle.Value,
PropertyInfo p => p.GetMethod?.MethodHandle.Value,
ConstructorInfo c => (nint?)c.MethodHandle.Value,
_ => null
};
return handle.HasValue && _map.TryGetValue(handle.Value, out var expr) ? expr : null;
}
private static void Register(Dictionary<nint, LambdaExpression> map, MethodBase m, string exprClass, string exprMethodName)
{
if (m is null) return;
var exprType = m.DeclaringType?.Assembly.GetType(exprClass) ?? typeof(ExpressionRegistry).Assembly.GetType(exprClass);
var exprMethod = exprType?.GetMethod(exprMethodName, BindingFlags.Static | BindingFlags.NonPublic);
if (exprMethod is null) return;
var expr = (LambdaExpression)exprMethod.Invoke(null, null)!;
// Apply declared transformers from the generated class (if any)
const string expressionSuffix = "_Expression";
if (exprMethodName.EndsWith(expressionSuffix, StringComparison.Ordinal))
{
var transformersSuffix = exprMethodName.Substring(0, exprMethodName.Length - expressionSuffix.Length) + "_Transformers";
var transformersMethod = exprType.GetMethod(transformersSuffix, BindingFlags.Static | BindingFlags.NonPublic);
if (transformersMethod?.Invoke(null, null) is global::ExpressiveSharp.IExpressionTreeTransformer[] transformers)
{
Expression transformed = expr;
foreach (var t in transformers) transformed = t.Transform(transformed);
if (transformed is LambdaExpression lambdaResult) expr = lambdaResult;
}
}
map[m.MethodHandle.Value] = expr;
}
}
}
// === PolyfillInterceptors_b1293e61.g.cs ===
// <auto-generated/>
#nullable disable
namespace ExpressiveSharp.Generated.Interceptors
{
internal static partial class PolyfillInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "E25IToyGqhczBT73gX3lSYQBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.Playground.Snippet.OrderSummaryDto> __Polyfill_Select_3e61_15_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, global::ExpressiveSharp.Docs.Playground.Snippet.OrderSummaryDto> __func)
{
// Source: o => new OrderSummaryDto(o.Id, o.Status.ToString(), o.ItemCount())
var i3e6115c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6115c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var i3e6115c5_expr_2 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Status", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Status
var i3e6115c5_expr_3 = global::System.Linq.Expressions.Expression.Constant(null, typeof(string));
var i3e6115c5_expr_4 = global::System.Linq.Expressions.Expression.Constant(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus.Refunded, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus));
var i3e6115c5_expr_5 = global::System.Linq.Expressions.Expression.Call(i3e6115c5_expr_4, typeof(global::System.Enum).GetMethod("ToString", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null), global::System.Array.Empty<global::System.Linq.Expressions.Expression>());
var i3e6115c5_expr_6 = global::System.Linq.Expressions.Expression.Equal(i3e6115c5_expr_2, i3e6115c5_expr_4);
var i3e6115c5_expr_7 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_6, i3e6115c5_expr_5, i3e6115c5_expr_3, typeof(string));
var i3e6115c5_expr_8 = global::System.Linq.Expressions.Expression.Constant(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus.Delivered, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus));
var i3e6115c5_expr_9 = global::System.Linq.Expressions.Expression.Call(i3e6115c5_expr_8, typeof(global::System.Enum).GetMethod("ToString", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null), global::System.Array.Empty<global::System.Linq.Expressions.Expression>());
var i3e6115c5_expr_10 = global::System.Linq.Expressions.Expression.Equal(i3e6115c5_expr_2, i3e6115c5_expr_8);
var i3e6115c5_expr_11 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_10, i3e6115c5_expr_9, i3e6115c5_expr_7, typeof(string));
var i3e6115c5_expr_12 = global::System.Linq.Expressions.Expression.Constant(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus.Shipped, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus));
var i3e6115c5_expr_13 = global::System.Linq.Expressions.Expression.Call(i3e6115c5_expr_12, typeof(global::System.Enum).GetMethod("ToString", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null), global::System.Array.Empty<global::System.Linq.Expressions.Expression>());
var i3e6115c5_expr_14 = global::System.Linq.Expressions.Expression.Equal(i3e6115c5_expr_2, i3e6115c5_expr_12);
var i3e6115c5_expr_15 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_14, i3e6115c5_expr_13, i3e6115c5_expr_11, typeof(string));
var i3e6115c5_expr_16 = global::System.Linq.Expressions.Expression.Constant(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus.Paid, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus));
var i3e6115c5_expr_17 = global::System.Linq.Expressions.Expression.Call(i3e6115c5_expr_16, typeof(global::System.Enum).GetMethod("ToString", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null), global::System.Array.Empty<global::System.Linq.Expressions.Expression>());
var i3e6115c5_expr_18 = global::System.Linq.Expressions.Expression.Equal(i3e6115c5_expr_2, i3e6115c5_expr_16);
var i3e6115c5_expr_19 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_18, i3e6115c5_expr_17, i3e6115c5_expr_15, typeof(string));
var i3e6115c5_expr_20 = global::System.Linq.Expressions.Expression.Constant(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus.Pending, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus));
var i3e6115c5_expr_21 = global::System.Linq.Expressions.Expression.Call(i3e6115c5_expr_20, typeof(global::System.Enum).GetMethod("ToString", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null), global::System.Array.Empty<global::System.Linq.Expressions.Expression>());
var i3e6115c5_expr_22 = global::System.Linq.Expressions.Expression.Equal(i3e6115c5_expr_2, i3e6115c5_expr_20);
var i3e6115c5_expr_23 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_22, i3e6115c5_expr_21, i3e6115c5_expr_19, typeof(string));
var i3e6115c5_expr_24 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("ItemCount", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), new global::System.Linq.Expressions.Expression[] { i3e6115c5_p_o }); // o.ItemCount()
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderSummaryDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(int), typeof(string), typeof(int) }, null), i3e6115c5_expr_1, i3e6115c5_expr_23, i3e6115c5_expr_24);
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, global::ExpressiveSharp.Docs.Playground.Snippet.OrderSummaryDto>>(i3e6115c5_expr_0, i3e6115c5_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>)source,
__lambda));
}
}
}
namespace System.Runtime.CompilerServices
{
[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : global::System.Attribute
{
public InterceptsLocationAttribute(int version, string data) { }
}
}db
.Orders
.Select(o => new OrderSummaryDto(o.Id, o.Status.ToString(), o.ItemCount()))
// Setup
public static class OrderExt
{
[Expressive]
public static int ItemCount(this Order o) => o.Items.Count();
}
public class OrderSummaryDto
{
public int Id { get; set; }
public string Description { get; set; } = "";
public int Items { get; set; }
public OrderSummaryDto() { }
[Expressive]
public OrderSummaryDto(int id, string description, int items)
{
Id = id;
Description = description;
Items = items;
}
}Generated SQL:
SELECT "o"."Id", CASE
WHEN "o"."Status" = 0 THEN 'Pending'
WHEN "o"."Status" = 1 THEN 'Paid'
WHEN "o"."Status" = 2 THEN 'Shipped'
WHEN "o"."Status" = 3 THEN 'Delivered'
WHEN "o"."Status" = 4 THEN 'Refunded'
END AS "Description", (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") AS "Items"
FROM "Orders" AS "o"TIP
Notice that o.ItemCount() is an [Expressive] extension method -- it gets expanded to o.Items.Count() automatically. Constructor projections compose naturally with computed members.
Inheritance Chains with Base Initializers
When your DTOs form an inheritance hierarchy, use : base(...) to avoid duplicating base-class assignments. The generator inlines both the base and derived assignments:
db
.Customers
.Select(c => new PremiumCustomerDto(c))
// Setup
public class CustomerBaseDto
{
public int Id { get; set; }
public string Name { get; set; } = "";
public CustomerBaseDto() { }
[Expressive]
public CustomerBaseDto(Customer c)
{
Id = c.Id;
Name = c.Name;
}
}
public class PremiumCustomerDto : CustomerBaseDto
{
public string Country { get; set; } = "";
public string Tier { get; set; } = "";
public PremiumCustomerDto() { }
[Expressive]
public PremiumCustomerDto(Customer c) : base(c)
{
Country = c.Country ?? "Unknown";
Tier = c.Orders.Count() >= 10 ? "Gold" : "Standard";
}
}SELECT COALESCE("c"."Country", 'Unknown') AS "Country", CASE
WHEN (
SELECT COUNT(*)
FROM "Orders" AS "o"
WHERE "c"."Id" = "o"."CustomerId") >= 10 THEN 'Gold'
ELSE 'Standard'
END AS "Tier"
FROM "Customers" AS "c"SELECT COALESCE(c."Country", 'Unknown') AS "Country", CASE
WHEN (
SELECT count(*)::int
FROM "Orders" AS o
WHERE c."Id" = o."CustomerId") >= 10 THEN 'Gold'
ELSE 'Standard'
END AS "Tier"
FROM "Customers" AS cSELECT COALESCE([c].[Country], N'Unknown') AS [Country], CASE
WHEN (
SELECT COUNT(*)
FROM [Orders] AS [o]
WHERE [c].[Id] = [o].[CustomerId]) >= 10 THEN N'Gold'
ELSE N'Standard'
END AS [Tier]
FROM [Customers] AS [c]playground.customers.Aggregate([
{
"$project" : {
"Country" : {
"$ifNull" : ["$Country", "Unknown"]
},
"Tier" : {
"$cond" : {
"if" : {
"$gte" : [
{ "$size" : "$Orders" },
10
]
},
"then" : "Gold",
"else" : "Standard"
}
},
"_id" : 0
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_CustomerBaseDto._ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Customer.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_CustomerBaseDto
{
// [Expressive]
// public CustomerBaseDto(Customer c)
// {
// Id = c.Id;
// Name = c.Name;
// }
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, global::ExpressiveSharp.Docs.Playground.Snippet.CustomerBaseDto>> _ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Customer_Expression()
{
var p_c = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer), "c");
var expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerBaseDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null));
var expr_1 = global::System.Linq.Expressions.Expression.Property(p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Id
var expr_2 = global::System.Linq.Expressions.Expression.Property(p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Name
var expr_3 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerBaseDto).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_1);
var expr_4 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerBaseDto).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_2);
var expr_5 = global::System.Linq.Expressions.Expression.MemberInit(expr_0, expr_3, expr_4);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, global::ExpressiveSharp.Docs.Playground.Snippet.CustomerBaseDto>>(expr_5, p_c);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_PremiumCustomerDto._ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Customer.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_PremiumCustomerDto
{
// [Expressive]
// public PremiumCustomerDto(Customer c) : base(c)
// {
// Country = c.Country ?? "Unknown";
// Tier = c.Orders.Count() >= 10 ? "Gold" : "Standard";
// }
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, global::ExpressiveSharp.Docs.Playground.Snippet.PremiumCustomerDto>> _ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Customer_Expression()
{
var p_c = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer), "c");
var expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.PremiumCustomerDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null));
var expr_2 = global::System.Linq.Expressions.Expression.Property(p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Country", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Country
var expr_3 = global::System.Linq.Expressions.Expression.Constant("Unknown", typeof(string)); // "Unknown"
var expr_1 = global::System.Linq.Expressions.Expression.Coalesce(expr_2, expr_3);
var expr_7 = global::System.Linq.Expressions.Expression.Property(p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Orders", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Orders
var expr_6 = global::System.Linq.Expressions.Expression.Call(global::System.Linq.Enumerable.First(global::System.Linq.Enumerable.Where(typeof(global::System.Linq.Enumerable).GetMethods(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static), m => m.Name == "Count" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.IsGenericType && !m.GetParameters()[0].ParameterType.IsGenericParameter)).MakeGenericMethod(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order)), new global::System.Linq.Expressions.Expression[] { expr_7 });
var expr_8 = global::System.Linq.Expressions.Expression.Constant(10, typeof(int)); // 10
var expr_5 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_6, expr_8);
var expr_9 = global::System.Linq.Expressions.Expression.Constant("Gold", typeof(string)); // "Gold"
var expr_10 = global::System.Linq.Expressions.Expression.Constant("Standard", typeof(string)); // "Standard"
var expr_4 = global::System.Linq.Expressions.Expression.Condition(expr_5, expr_9, expr_10, typeof(string));
var expr_11 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.PremiumCustomerDto).GetProperty("Country", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_1);
var expr_12 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.PremiumCustomerDto).GetProperty("Tier", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_4);
var expr_13 = global::System.Linq.Expressions.Expression.MemberInit(expr_0, expr_11, expr_12);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, global::ExpressiveSharp.Docs.Playground.Snippet.PremiumCustomerDto>>(expr_13, p_c);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_CustomerBaseDto.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_CustomerBaseDto { }
}
// === ExpressiveSharp_Docs_Playground_Snippet_PremiumCustomerDto.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_PremiumCustomerDto { }
}
// === ExpressionRegistry.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static class ExpressionRegistry
{
private static Dictionary<nint, LambdaExpression> Build()
{
const BindingFlags allFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
var map = new Dictionary<nint, LambdaExpression>();
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerBaseDto).GetConstructor(allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_CustomerBaseDto", "_ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Customer_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.PremiumCustomerDto).GetConstructor(allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_PremiumCustomerDto", "_ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Customer_Expression");
return map;
}
private static volatile Dictionary<nint, LambdaExpression> _map = Build();
internal static void ResetMap() => _map = Build();
public static LambdaExpression TryGet(MemberInfo member)
{
var handle = member switch
{
MethodInfo m => (nint?)m.MethodHandle.Value,
PropertyInfo p => p.GetMethod?.MethodHandle.Value,
ConstructorInfo c => (nint?)c.MethodHandle.Value,
_ => null
};
return handle.HasValue && _map.TryGetValue(handle.Value, out var expr) ? expr : null;
}
private static void Register(Dictionary<nint, LambdaExpression> map, MethodBase m, string exprClass, string exprMethodName)
{
if (m is null) return;
var exprType = m.DeclaringType?.Assembly.GetType(exprClass) ?? typeof(ExpressionRegistry).Assembly.GetType(exprClass);
var exprMethod = exprType?.GetMethod(exprMethodName, BindingFlags.Static | BindingFlags.NonPublic);
if (exprMethod is null) return;
var expr = (LambdaExpression)exprMethod.Invoke(null, null)!;
// Apply declared transformers from the generated class (if any)
const string expressionSuffix = "_Expression";
if (exprMethodName.EndsWith(expressionSuffix, StringComparison.Ordinal))
{
var transformersSuffix = exprMethodName.Substring(0, exprMethodName.Length - expressionSuffix.Length) + "_Transformers";
var transformersMethod = exprType.GetMethod(transformersSuffix, BindingFlags.Static | BindingFlags.NonPublic);
if (transformersMethod?.Invoke(null, null) is global::ExpressiveSharp.IExpressionTreeTransformer[] transformers)
{
Expression transformed = expr;
foreach (var t in transformers) transformed = t.Transform(transformed);
if (transformed is LambdaExpression lambdaResult) expr = lambdaResult;
}
}
map[m.MethodHandle.Value] = expr;
}
}
}
// === PolyfillInterceptors_b1293e61.g.cs ===
// <auto-generated/>
#nullable disable
namespace ExpressiveSharp.Generated.Interceptors
{
internal static partial class PolyfillInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "Y1w7nzu5Zw8OZDRhhkL61IIBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.Playground.Snippet.PremiumCustomerDto> __Polyfill_Select_3e61_14_24(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, global::ExpressiveSharp.Docs.Playground.Snippet.PremiumCustomerDto> __func)
{
// Source: c => new PremiumCustomerDto(c)
var i3e6114c24_p_c = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer), "c");
var i3e6114c24_expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.PremiumCustomerDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer) }, null), i3e6114c24_p_c); // new PremiumCustomerDto(c)
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, global::ExpressiveSharp.Docs.Playground.Snippet.PremiumCustomerDto>>(i3e6114c24_expr_0, i3e6114c24_p_c);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer>)source,
__lambda));
}
}
}
namespace System.Runtime.CompilerServices
{
[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : global::System.Attribute
{
public InterceptsLocationAttribute(int version, string data) { }
}
}db
.Customers
.Select(c => new PremiumCustomerDto(c))
// Setup
public class CustomerBaseDto
{
public int Id { get; set; }
public string Name { get; set; } = "";
public CustomerBaseDto() { }
[Expressive]
public CustomerBaseDto(Customer c)
{
Id = c.Id;
Name = c.Name;
}
}
public class PremiumCustomerDto : CustomerBaseDto
{
public string Country { get; set; } = "";
public string Tier { get; set; } = "";
public PremiumCustomerDto() { }
[Expressive]
public PremiumCustomerDto(Customer c) : base(c)
{
Country = c.Country ?? "Unknown";
Tier = c.Orders.Count() >= 10 ? "Gold" : "Standard";
}
}Generated SQL:
SELECT COALESCE("c"."Country", 'Unknown') AS "Country", CASE
WHEN (
SELECT COUNT(*)
FROM "Orders" AS "o"
WHERE "c"."Id" = "o"."CustomerId") >= 10 THEN 'Gold'
ELSE 'Standard'
END AS "Tier"
FROM "Customers" AS "c"All fields -- Id, Name, Country, and Tier -- are projected in a single query.
Constructor Overloads
If you need different projections from the same DTO, use constructor overloads. Each gets its own generated expression:
db
.Orders
.Select(o => new OrderDto(o))
// Setup
public class OrderDto
{
public int Id { get; set; }
public int ItemCount { get; set; }
public string? CustomerName { get; set; }
public OrderDto() { }
// Full projection (with customer name -- requires navigation join)
[Expressive]
public OrderDto(Order o)
{
Id = o.Id;
ItemCount = o.Items.Count();
CustomerName = o.Customer.Name;
}
// Lightweight projection (no navigation join needed)
[Expressive]
public OrderDto(Order o, bool lightweight)
{
Id = o.Id;
ItemCount = o.Items.Count();
CustomerName = null;
}
}SELECT "o"."Id", (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") AS "ItemCount", "c"."Name" AS "CustomerName"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"SELECT o."Id", (
SELECT count(*)::int
FROM "LineItems" AS l
WHERE o."Id" = l."OrderId") AS "ItemCount", c."Name" AS "CustomerName"
FROM "Orders" AS o
INNER JOIN "Customers" AS c ON o."CustomerId" = c."Id"SELECT [o].[Id], (
SELECT COUNT(*)
FROM [LineItems] AS [l]
WHERE [o].[Id] = [l].[OrderId]) AS [ItemCount], [c].[Name] AS [CustomerName]
FROM [Orders] AS [o]
INNER JOIN [Customers] AS [c] ON [o].[CustomerId] = [c].[Id]playground.orders.Aggregate([
{
"$project" : {
"_id" : "$_id",
"ItemCount" : { "$size" : "$Items" },
"CustomerName" : "$Customer.Name"
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderDto._ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderDto
{
// // Full projection (with customer name -- requires navigation join)
// [Expressive]
// public OrderDto(Order o)
// {
// Id = o.Id;
// ItemCount = o.Items.Count();
// CustomerName = o.Customer.Name;
// }
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto>> _ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression()
{
var p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null));
var expr_1 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var expr_3 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Items", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Items
var expr_2 = global::System.Linq.Expressions.Expression.Call(global::System.Linq.Enumerable.First(global::System.Linq.Enumerable.Where(typeof(global::System.Linq.Enumerable).GetMethods(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static), m => m.Name == "Count" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.IsGenericType && !m.GetParameters()[0].ParameterType.IsGenericParameter)).MakeGenericMethod(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem)), new global::System.Linq.Expressions.Expression[] { expr_3 });
var expr_5 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Customer
var expr_4 = global::System.Linq.Expressions.Expression.Property(expr_5, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_6 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_1);
var expr_7 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetProperty("ItemCount", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_2);
var expr_8 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetProperty("CustomerName", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_4);
var expr_9 = global::System.Linq.Expressions.Expression.MemberInit(expr_0, expr_6, expr_7, expr_8);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto>>(expr_9, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderDto._ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_bool.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderDto
{
// // Lightweight projection (no navigation join needed)
// [Expressive]
// public OrderDto(Order o, bool lightweight)
// {
// Id = o.Id;
// ItemCount = o.Items.Count();
// CustomerName = null;
// }
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool, global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto>> _ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_bool_Expression()
{
var p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var p_lightweight = global::System.Linq.Expressions.Expression.Parameter(typeof(bool), "lightweight");
var expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null));
var expr_1 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var expr_3 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Items", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Items
var expr_2 = global::System.Linq.Expressions.Expression.Call(global::System.Linq.Enumerable.First(global::System.Linq.Enumerable.Where(typeof(global::System.Linq.Enumerable).GetMethods(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static), m => m.Name == "Count" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.IsGenericType && !m.GetParameters()[0].ParameterType.IsGenericParameter)).MakeGenericMethod(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem)), new global::System.Linq.Expressions.Expression[] { expr_3 });
var expr_5 = global::System.Linq.Expressions.Expression.Constant(null, typeof(object)); // null
var expr_4 = global::System.Linq.Expressions.Expression.Convert(expr_5, typeof(string));
var expr_6 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_1);
var expr_7 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetProperty("ItemCount", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_2);
var expr_8 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetProperty("CustomerName", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_4);
var expr_9 = global::System.Linq.Expressions.Expression.MemberInit(expr_0, expr_6, expr_7, expr_8);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool, global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto>>(expr_9, p_o, p_lightweight);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderDto.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderDto { }
}
// === ExpressionRegistry.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static class ExpressionRegistry
{
private static Dictionary<nint, LambdaExpression> Build()
{
const BindingFlags allFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
var map = new Dictionary<nint, LambdaExpression>();
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetConstructor(allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderDto", "_ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetConstructor(allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), typeof(bool) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderDto", "_ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_bool_Expression");
return map;
}
private static volatile Dictionary<nint, LambdaExpression> _map = Build();
internal static void ResetMap() => _map = Build();
public static LambdaExpression TryGet(MemberInfo member)
{
var handle = member switch
{
MethodInfo m => (nint?)m.MethodHandle.Value,
PropertyInfo p => p.GetMethod?.MethodHandle.Value,
ConstructorInfo c => (nint?)c.MethodHandle.Value,
_ => null
};
return handle.HasValue && _map.TryGetValue(handle.Value, out var expr) ? expr : null;
}
private static void Register(Dictionary<nint, LambdaExpression> map, MethodBase m, string exprClass, string exprMethodName)
{
if (m is null) return;
var exprType = m.DeclaringType?.Assembly.GetType(exprClass) ?? typeof(ExpressionRegistry).Assembly.GetType(exprClass);
var exprMethod = exprType?.GetMethod(exprMethodName, BindingFlags.Static | BindingFlags.NonPublic);
if (exprMethod is null) return;
var expr = (LambdaExpression)exprMethod.Invoke(null, null)!;
// Apply declared transformers from the generated class (if any)
const string expressionSuffix = "_Expression";
if (exprMethodName.EndsWith(expressionSuffix, StringComparison.Ordinal))
{
var transformersSuffix = exprMethodName.Substring(0, exprMethodName.Length - expressionSuffix.Length) + "_Transformers";
var transformersMethod = exprType.GetMethod(transformersSuffix, BindingFlags.Static | BindingFlags.NonPublic);
if (transformersMethod?.Invoke(null, null) is global::ExpressiveSharp.IExpressionTreeTransformer[] transformers)
{
Expression transformed = expr;
foreach (var t in transformers) transformed = t.Transform(transformed);
if (transformed is LambdaExpression lambdaResult) expr = lambdaResult;
}
}
map[m.MethodHandle.Value] = expr;
}
}
}
// === PolyfillInterceptors_b1293e61.g.cs ===
// <auto-generated/>
#nullable disable
namespace ExpressiveSharp.Generated.Interceptors
{
internal static partial class PolyfillInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "vI6GeV3uhuEkEnCq8l4Ban8BAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto> __Polyfill_Select_3e61_14_21(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto> __func)
{
// Source: o => new OrderDto(o)
var i3e6114c21_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6114c21_expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), i3e6114c21_p_o); // new OrderDto(o)
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto>>(i3e6114c21_expr_0, i3e6114c21_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>)source,
__lambda));
}
}
}
namespace System.Runtime.CompilerServices
{
[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : global::System.Attribute
{
public InterceptsLocationAttribute(int version, string data) { }
}
}db
.Orders
.Select(o => new OrderDto(o))
// Setup
public class OrderDto
{
public int Id { get; set; }
public int ItemCount { get; set; }
public string? CustomerName { get; set; }
public OrderDto() { }
// Full projection (with customer name -- requires navigation join)
[Expressive]
public OrderDto(Order o)
{
Id = o.Id;
ItemCount = o.Items.Count();
CustomerName = o.Customer.Name;
}
// Lightweight projection (no navigation join needed)
[Expressive]
public OrderDto(Order o, bool lightweight)
{
Id = o.Id;
ItemCount = o.Items.Count();
CustomerName = null;
}
}Generated SQL:
SELECT "o"."Id", (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") AS "ItemCount", "c"."Name" AS "CustomerName"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"The lightweight variant is called the same way, just with the extra argument:
db
.Orders
.Select(o => new OrderDto(o, true))
// Setup
public class OrderDto
{
public int Id { get; set; }
public int ItemCount { get; set; }
public string? CustomerName { get; set; }
public OrderDto() { }
[Expressive]
public OrderDto(Order o)
{
Id = o.Id;
ItemCount = o.Items.Count();
CustomerName = o.Customer.Name;
}
[Expressive]
public OrderDto(Order o, bool lightweight)
{
Id = o.Id;
ItemCount = o.Items.Count();
CustomerName = null;
}
}SELECT "o"."Id", (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") AS "ItemCount", NULL AS "CustomerName"
FROM "Orders" AS "o"SELECT o."Id", (
SELECT count(*)::int
FROM "LineItems" AS l
WHERE o."Id" = l."OrderId") AS "ItemCount", NULL AS "CustomerName"
FROM "Orders" AS oSELECT [o].[Id], (
SELECT COUNT(*)
FROM [LineItems] AS [l]
WHERE [o].[Id] = [l].[OrderId]) AS [ItemCount], NULL AS [CustomerName]
FROM [Orders] AS [o]playground.orders.Aggregate([
{
"$project" : {
"_id" : "$_id",
"ItemCount" : { "$size" : "$Items" },
"CustomerName" : null
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderDto._ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderDto
{
// [Expressive]
// public OrderDto(Order o)
// {
// Id = o.Id;
// ItemCount = o.Items.Count();
// CustomerName = o.Customer.Name;
// }
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto>> _ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression()
{
var p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null));
var expr_1 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var expr_3 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Items", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Items
var expr_2 = global::System.Linq.Expressions.Expression.Call(global::System.Linq.Enumerable.First(global::System.Linq.Enumerable.Where(typeof(global::System.Linq.Enumerable).GetMethods(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static), m => m.Name == "Count" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.IsGenericType && !m.GetParameters()[0].ParameterType.IsGenericParameter)).MakeGenericMethod(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem)), new global::System.Linq.Expressions.Expression[] { expr_3 });
var expr_5 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Customer
var expr_4 = global::System.Linq.Expressions.Expression.Property(expr_5, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_6 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_1);
var expr_7 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetProperty("ItemCount", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_2);
var expr_8 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetProperty("CustomerName", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_4);
var expr_9 = global::System.Linq.Expressions.Expression.MemberInit(expr_0, expr_6, expr_7, expr_8);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto>>(expr_9, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderDto._ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_bool.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderDto
{
// [Expressive]
// public OrderDto(Order o, bool lightweight)
// {
// Id = o.Id;
// ItemCount = o.Items.Count();
// CustomerName = null;
// }
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool, global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto>> _ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_bool_Expression()
{
var p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var p_lightweight = global::System.Linq.Expressions.Expression.Parameter(typeof(bool), "lightweight");
var expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null));
var expr_1 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var expr_3 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Items", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Items
var expr_2 = global::System.Linq.Expressions.Expression.Call(global::System.Linq.Enumerable.First(global::System.Linq.Enumerable.Where(typeof(global::System.Linq.Enumerable).GetMethods(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static), m => m.Name == "Count" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.IsGenericType && !m.GetParameters()[0].ParameterType.IsGenericParameter)).MakeGenericMethod(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem)), new global::System.Linq.Expressions.Expression[] { expr_3 });
var expr_5 = global::System.Linq.Expressions.Expression.Constant(null, typeof(object)); // null
var expr_4 = global::System.Linq.Expressions.Expression.Convert(expr_5, typeof(string));
var expr_6 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_1);
var expr_7 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetProperty("ItemCount", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_2);
var expr_8 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetProperty("CustomerName", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_4);
var expr_9 = global::System.Linq.Expressions.Expression.MemberInit(expr_0, expr_6, expr_7, expr_8);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool, global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto>>(expr_9, p_o, p_lightweight);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderDto.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderDto { }
}
// === ExpressionRegistry.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static class ExpressionRegistry
{
private static Dictionary<nint, LambdaExpression> Build()
{
const BindingFlags allFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
var map = new Dictionary<nint, LambdaExpression>();
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetConstructor(allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderDto", "_ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetConstructor(allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), typeof(bool) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderDto", "_ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_bool_Expression");
return map;
}
private static volatile Dictionary<nint, LambdaExpression> _map = Build();
internal static void ResetMap() => _map = Build();
public static LambdaExpression TryGet(MemberInfo member)
{
var handle = member switch
{
MethodInfo m => (nint?)m.MethodHandle.Value,
PropertyInfo p => p.GetMethod?.MethodHandle.Value,
ConstructorInfo c => (nint?)c.MethodHandle.Value,
_ => null
};
return handle.HasValue && _map.TryGetValue(handle.Value, out var expr) ? expr : null;
}
private static void Register(Dictionary<nint, LambdaExpression> map, MethodBase m, string exprClass, string exprMethodName)
{
if (m is null) return;
var exprType = m.DeclaringType?.Assembly.GetType(exprClass) ?? typeof(ExpressionRegistry).Assembly.GetType(exprClass);
var exprMethod = exprType?.GetMethod(exprMethodName, BindingFlags.Static | BindingFlags.NonPublic);
if (exprMethod is null) return;
var expr = (LambdaExpression)exprMethod.Invoke(null, null)!;
// Apply declared transformers from the generated class (if any)
const string expressionSuffix = "_Expression";
if (exprMethodName.EndsWith(expressionSuffix, StringComparison.Ordinal))
{
var transformersSuffix = exprMethodName.Substring(0, exprMethodName.Length - expressionSuffix.Length) + "_Transformers";
var transformersMethod = exprType.GetMethod(transformersSuffix, BindingFlags.Static | BindingFlags.NonPublic);
if (transformersMethod?.Invoke(null, null) is global::ExpressiveSharp.IExpressionTreeTransformer[] transformers)
{
Expression transformed = expr;
foreach (var t in transformers) transformed = t.Transform(transformed);
if (transformed is LambdaExpression lambdaResult) expr = lambdaResult;
}
}
map[m.MethodHandle.Value] = expr;
}
}
}
// === PolyfillInterceptors_b1293e61.g.cs ===
// <auto-generated/>
#nullable disable
namespace ExpressiveSharp.Generated.Interceptors
{
internal static partial class PolyfillInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "S8urpwqxcEqJKhipCB9DPn8BAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto> __Polyfill_Select_3e61_14_21(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto> __func)
{
// Source: o => new OrderDto(o, true)
var i3e6114c21_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6114c21_expr_1 = global::System.Linq.Expressions.Expression.Constant(true, typeof(bool)); // true
var i3e6114c21_expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), typeof(bool) }, null), i3e6114c21_p_o, i3e6114c21_expr_1);
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, global::ExpressiveSharp.Docs.Playground.Snippet.OrderDto>>(i3e6114c21_expr_0, i3e6114c21_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>)source,
__lambda));
}
}
}
namespace System.Runtime.CompilerServices
{
[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : global::System.Attribute
{
public InterceptsLocationAttribute(int version, string data) { }
}
}db
.Orders
.Select(o => new OrderDto(o, true))
// Setup
public class OrderDto
{
public int Id { get; set; }
public int ItemCount { get; set; }
public string? CustomerName { get; set; }
public OrderDto() { }
[Expressive]
public OrderDto(Order o)
{
Id = o.Id;
ItemCount = o.Items.Count();
CustomerName = o.Customer.Name;
}
[Expressive]
public OrderDto(Order o, bool lightweight)
{
Id = o.Id;
ItemCount = o.Items.Count();
CustomerName = null;
}
}Generated SQL:
SELECT "o"."Id", (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") AS "ItemCount", NULL AS "CustomerName"
FROM "Orders" AS "o"Using Switch Expressions in Constructors
Constructor bodies support the same modern C# syntax as other [Expressive] members:
db
.Products
.Select(p => new ProductDto(p))
// Setup
public class ProductDto
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
public string PriceTier { get; set; } = "";
public ProductDto() { }
[Expressive]
public ProductDto(Product p)
{
Id = p.Id;
Name = p.Name;
Price = p.ListPrice;
PriceTier = p.ListPrice switch
{
> 500m => "Premium",
> 100m => "Standard",
_ => "Budget"
};
}
}SELECT "p"."Id", "p"."Name", "p"."ListPrice" AS "Price", CASE
WHEN ef_compare("p"."ListPrice", '500.0') > 0 THEN 'Premium'
WHEN ef_compare("p"."ListPrice", '100.0') > 0 THEN 'Standard'
ELSE 'Budget'
END AS "PriceTier"
FROM "Products" AS "p"SELECT p."Id", p."Name", p."ListPrice" AS "Price", CASE
WHEN p."ListPrice" > 500.0 THEN 'Premium'
WHEN p."ListPrice" > 100.0 THEN 'Standard'
ELSE 'Budget'
END AS "PriceTier"
FROM "Products" AS pSELECT [p].[Id], [p].[Name], [p].[ListPrice] AS [Price], CASE
WHEN [p].[ListPrice] > 500.0 THEN N'Premium'
WHEN [p].[ListPrice] > 100.0 THEN N'Standard'
ELSE N'Budget'
END AS [PriceTier]
FROM [Products] AS [p]playground.products.Aggregate([
{
"$project" : {
"_id" : "$_id",
"Name" : "$Name",
"Price" : "$ListPrice",
"PriceTier" : {
"$cond" : {
"if" : {
"$gt" : [
"$ListPrice",
{ "$numberDecimal" : "500" }
]
},
"then" : "Premium",
"else" : {
"$cond" : {
"if" : {
"$gt" : [
"$ListPrice",
{ "$numberDecimal" : "100" }
]
},
"then" : "Standard",
"else" : "Budget"
}
}
}
}
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_ProductDto._ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Product.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_ProductDto
{
// [Expressive]
// public ProductDto(Product p)
// {
// Id = p.Id;
// Name = p.Name;
// Price = p.ListPrice;
// PriceTier = p.ListPrice switch
// {
// > 500m => "Premium",
// > 100m => "Standard",
// _ => "Budget"
// };
// }
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, global::ExpressiveSharp.Docs.Playground.Snippet.ProductDto>> _ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Product_Expression()
{
var p_p = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product), "p");
var expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { }, null));
var expr_1 = global::System.Linq.Expressions.Expression.Property(p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.Id
var expr_2 = global::System.Linq.Expressions.Expression.Property(p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.Name
var expr_3 = global::System.Linq.Expressions.Expression.Property(p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("ListPrice", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.ListPrice
var expr_4 = global::System.Linq.Expressions.Expression.Property(p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("ListPrice", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.ListPrice
var expr_5 = global::System.Linq.Expressions.Expression.Constant("Budget", typeof(string)); // "Budget"
var expr_7 = global::System.Linq.Expressions.Expression.Constant(100m, typeof(decimal)); // 100m
var expr_6 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThan, expr_4, expr_7);
var expr_8 = global::System.Linq.Expressions.Expression.Constant("Standard", typeof(string)); // "Standard"
var expr_9 = global::System.Linq.Expressions.Expression.Condition(expr_6, expr_8, expr_5, typeof(string));
var expr_11 = global::System.Linq.Expressions.Expression.Constant(500m, typeof(decimal)); // 500m
var expr_10 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThan, expr_4, expr_11);
var expr_12 = global::System.Linq.Expressions.Expression.Constant("Premium", typeof(string)); // "Premium"
var expr_13 = global::System.Linq.Expressions.Expression.Condition(expr_10, expr_12, expr_9, typeof(string));
var expr_14 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductDto).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_1);
var expr_15 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductDto).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_2);
var expr_16 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductDto).GetProperty("Price", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_3);
var expr_17 = global::System.Linq.Expressions.Expression.Bind(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductDto).GetProperty("PriceTier", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance), expr_13);
var expr_18 = global::System.Linq.Expressions.Expression.MemberInit(expr_0, expr_14, expr_15, expr_16, expr_17);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, global::ExpressiveSharp.Docs.Playground.Snippet.ProductDto>>(expr_18, p_p);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_ProductDto.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_ProductDto { }
}
// === ExpressionRegistry.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static class ExpressionRegistry
{
private static Dictionary<nint, LambdaExpression> Build()
{
const BindingFlags allFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
var map = new Dictionary<nint, LambdaExpression>();
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductDto).GetConstructor(allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_ProductDto", "_ctor_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Product_Expression");
return map;
}
private static volatile Dictionary<nint, LambdaExpression> _map = Build();
internal static void ResetMap() => _map = Build();
public static LambdaExpression TryGet(MemberInfo member)
{
var handle = member switch
{
MethodInfo m => (nint?)m.MethodHandle.Value,
PropertyInfo p => p.GetMethod?.MethodHandle.Value,
ConstructorInfo c => (nint?)c.MethodHandle.Value,
_ => null
};
return handle.HasValue && _map.TryGetValue(handle.Value, out var expr) ? expr : null;
}
private static void Register(Dictionary<nint, LambdaExpression> map, MethodBase m, string exprClass, string exprMethodName)
{
if (m is null) return;
var exprType = m.DeclaringType?.Assembly.GetType(exprClass) ?? typeof(ExpressionRegistry).Assembly.GetType(exprClass);
var exprMethod = exprType?.GetMethod(exprMethodName, BindingFlags.Static | BindingFlags.NonPublic);
if (exprMethod is null) return;
var expr = (LambdaExpression)exprMethod.Invoke(null, null)!;
// Apply declared transformers from the generated class (if any)
const string expressionSuffix = "_Expression";
if (exprMethodName.EndsWith(expressionSuffix, StringComparison.Ordinal))
{
var transformersSuffix = exprMethodName.Substring(0, exprMethodName.Length - expressionSuffix.Length) + "_Transformers";
var transformersMethod = exprType.GetMethod(transformersSuffix, BindingFlags.Static | BindingFlags.NonPublic);
if (transformersMethod?.Invoke(null, null) is global::ExpressiveSharp.IExpressionTreeTransformer[] transformers)
{
Expression transformed = expr;
foreach (var t in transformers) transformed = t.Transform(transformed);
if (transformed is LambdaExpression lambdaResult) expr = lambdaResult;
}
}
map[m.MethodHandle.Value] = expr;
}
}
}
// === PolyfillInterceptors_b1293e61.g.cs ===
// <auto-generated/>
#nullable disable
namespace ExpressiveSharp.Generated.Interceptors
{
internal static partial class PolyfillInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "LOtA3ssvVKb9OKV6nEuw24EBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.Playground.Snippet.ProductDto> __Polyfill_Select_3e61_14_23(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, global::ExpressiveSharp.Docs.Playground.Snippet.ProductDto> __func)
{
// Source: p => new ProductDto(p)
var i3e6114c23_p_p = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product), "p");
var i3e6114c23_expr_0 = global::System.Linq.Expressions.Expression.New(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductDto).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), i3e6114c23_p_p); // new ProductDto(p)
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, global::ExpressiveSharp.Docs.Playground.Snippet.ProductDto>>(i3e6114c23_expr_0, i3e6114c23_p_p);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product>)source,
__lambda));
}
}
}
namespace System.Runtime.CompilerServices
{
[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : global::System.Attribute
{
public InterceptsLocationAttribute(int version, string data) { }
}
}db
.Products
.Select(p => new ProductDto(p))
// Setup
public class ProductDto
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
public string PriceTier { get; set; } = "";
public ProductDto() { }
[Expressive]
public ProductDto(Product p)
{
Id = p.Id;
Name = p.Name;
Price = p.ListPrice;
PriceTier = p.ListPrice switch
{
> 500m => "Premium",
> 100m => "Standard",
_ => "Budget"
};
}
}Generated SQL:
SELECT "p"."Id", "p"."Name", "p"."ListPrice" AS "Price", CASE
WHEN ef_compare("p"."ListPrice", '500.0') > 0 THEN 'Premium'
WHEN ef_compare("p"."ListPrice", '100.0') > 0 THEN 'Standard'
ELSE 'Budget'
END AS "PriceTier"
FROM "Products" AS "p"Using [ExpressiveForConstructor] for External Types
If you do not own the DTO type (third-party library, shared package), use [ExpressiveForConstructor] to provide the expression body externally:
using ExpressiveSharp.Mapping;
[ExpressiveForConstructor(typeof(ExternalOrderDto))]
static ExternalOrderDto CreateDto(int id, string name)
=> new ExternalOrderDto { Id = id, Name = name };See External Member Mapping for details.
Tips
Always add a parameterless constructor
The generator emits new T() { ... } syntax. If the parameterless constructor is missing, the build will fail.
Keep mappings pure
No side effects, no calls to non-expressible methods. Everything in the constructor body must be translatable to SQL.
INFO
Constructor bodies are block-bodied by nature, but they do not require AllowBlockBody = true — the generator handles them automatically. UseExpressives() registers the FlattenBlockExpressions transformer to flatten them for EF Core.
See Also
- Computed Entity Properties -- reusable computed values referenced in constructor projections
- External Member Mapping --
[ExpressiveForConstructor]for types you do not own - Scoring and Classification -- switch expressions and pattern matching in projections
