Modern Syntax in LINQ Chains
This recipe shows how to use modern C# syntax -- null-conditional operators, switch expressions, pattern matching -- directly inside LINQ method chains like .Where(), .Select(), and .OrderBy(), without defining separate [Expressive] members.
The Problem
Expression trees only support a restricted subset of C#. Try to use ?. in a LINQ lambda and you get:
error CS8072: An expression tree lambda may not contain a null propagating operatorThe same limitation applies to switch expressions, pattern matching, and many other modern C# features. Without ExpressiveSharp, your only option is to write verbose ternary chains:
// Without ExpressiveSharp -- ugly ternary chains
var results = dbContext.Orders
.Where(o => o.Customer != null ? o.Customer.Email != null : false)
.Select(o => new
{
o.Id,
Name = o.Customer != null ? o.Customer.Name : "Unknown",
Grade = o.Items.Count() >= 10 ? "Premium" : (o.Items.Count() >= 5 ? "Standard" : "Budget")
})
.ToList();Three Solutions
ExpressiveSharp offers three ways to use modern syntax in LINQ chains. Each targets a different scenario.
1. IExpressiveQueryable<T> with .AsExpressive()
Works with any IQueryable<T> -- not tied to EF Core:
db
.Orders
.Where(o => o.Customer?.Email != null)
.Select(o => new
{
o.Id,
Name = o.Customer?.Name ?? "Unknown",
Grade = o.Items.Count() switch
{
>= 10 => "Premium",
>= 5 => "Standard",
_ => "Budget"
}
})
.OrderBy(x => x.Name)SELECT "o"."Id", "c"."Name", CASE
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") >= 10 THEN 'Premium'
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId") >= 5 THEN 'Standard'
ELSE 'Budget'
END AS "Grade"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "c"."Email" IS NOT NULL
ORDER BY "c"."Name"SELECT o."Id", c."Name", CASE
WHEN (
SELECT count(*)::int
FROM "LineItems" AS l
WHERE o."Id" = l."OrderId") >= 10 THEN 'Premium'
WHEN (
SELECT count(*)::int
FROM "LineItems" AS l0
WHERE o."Id" = l0."OrderId") >= 5 THEN 'Standard'
ELSE 'Budget'
END AS "Grade"
FROM "Orders" AS o
INNER JOIN "Customers" AS c ON o."CustomerId" = c."Id"
WHERE c."Email" IS NOT NULL
ORDER BY c."Name"SELECT [o].[Id], [c].[Name], CASE
WHEN (
SELECT COUNT(*)
FROM [LineItems] AS [l]
WHERE [o].[Id] = [l].[OrderId]) >= 10 THEN N'Premium'
WHEN (
SELECT COUNT(*)
FROM [LineItems] AS [l0]
WHERE [o].[Id] = [l0].[OrderId]) >= 5 THEN N'Standard'
ELSE N'Budget'
END AS [Grade]
FROM [Orders] AS [o]
INNER JOIN [Customers] AS [c] ON [o].[CustomerId] = [c].[Id]
WHERE [c].[Email] IS NOT NULL
ORDER BY [c].[Name]playground.orders.Aggregate([
{
"$match" : {
"Customer.Email" : { "$ne" : null }
}
},
{
"$project" : {
"_id" : "$_id",
"Name" : {
"$ifNull" : ["$Customer.Name", "Unknown"]
},
"Grade" : {
"$cond" : {
"if" : {
"$gte" : [
{ "$size" : "$Items" },
10
]
},
"then" : "Premium",
"else" : {
"$cond" : {
"if" : {
"$gte" : [
{ "$size" : "$Items" },
5
]
},
"then" : "Standard",
"else" : "Budget"
}
}
}
}
}
},
{
"$sort" : { "Name" : 1 }
}
])// === PolyfillInterceptors_b1293e61.g.cs ===
// <auto-generated/>
#nullable disable
namespace ExpressiveSharp.Generated.Interceptors
{
internal static partial class PolyfillInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "XLUkkk++MsGOKw3GbtLwr6cCAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T0> __Polyfill_OrderBy_3e61_27_5<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: x => x.Name
var i3e6127c5_p_x = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "x");
var i3e6127c5_expr_0 = global::System.Linq.Expressions.Expression.Property(i3e6127c5_p_x, typeof(T0).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // x.Name
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6127c5_expr_0, i3e6127c5_p_x);
return (global::ExpressiveSharp.IExpressiveQueryable<T0>)(object)
global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.OrderBy(
(global::System.Linq.IQueryable<T0>)(object)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "XLUkkk++MsGOKw3GbtLwr68BAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T1> __Polyfill_Select_3e61_16_5<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: o => new { o.Id, Name = o.Customer?.Name ?? "Unknown", Grade = o.Items.Count() switch { >= 10 => "Premium", >= 5 => "Standard", _ => "Budget" } }
var i3e6116c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "o");
var i3e6116c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_o, typeof(T0).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var i3e6116c5_expr_3 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_o, typeof(T0).GetProperty("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Customer
var i3e6116c5_expr_4 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_expr_3, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // .Name
var i3e6116c5_expr_6 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer));
var i3e6116c5_expr_7 = global::System.Linq.Expressions.Expression.NotEqual(i3e6116c5_expr_3, i3e6116c5_expr_6);
var i3e6116c5_expr_8 = global::System.Linq.Expressions.Expression.Default(typeof(string));
var i3e6116c5_expr_5 = global::System.Linq.Expressions.Expression.Condition(i3e6116c5_expr_7, i3e6116c5_expr_4, i3e6116c5_expr_8, typeof(string));
var i3e6116c5_expr_9 = global::System.Linq.Expressions.Expression.Constant("Unknown", typeof(string)); // "Unknown"
var i3e6116c5_expr_2 = global::System.Linq.Expressions.Expression.Coalesce(i3e6116c5_expr_5, i3e6116c5_expr_9);
var i3e6116c5_expr_11 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_o, typeof(T0).GetProperty("Items", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Items
var i3e6116c5_expr_10 = 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[] { i3e6116c5_expr_11 });
var i3e6116c5_expr_12 = global::System.Linq.Expressions.Expression.Constant("Budget", typeof(string)); // "Budget"
var i3e6116c5_expr_14 = global::System.Linq.Expressions.Expression.Constant(5, typeof(int)); // 5
var i3e6116c5_expr_13 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, i3e6116c5_expr_10, i3e6116c5_expr_14);
var i3e6116c5_expr_15 = global::System.Linq.Expressions.Expression.Constant("Standard", typeof(string)); // "Standard"
var i3e6116c5_expr_16 = global::System.Linq.Expressions.Expression.Condition(i3e6116c5_expr_13, i3e6116c5_expr_15, i3e6116c5_expr_12, typeof(string));
var i3e6116c5_expr_18 = global::System.Linq.Expressions.Expression.Constant(10, typeof(int)); // 10
var i3e6116c5_expr_17 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, i3e6116c5_expr_10, i3e6116c5_expr_18);
var i3e6116c5_expr_19 = global::System.Linq.Expressions.Expression.Constant("Premium", typeof(string)); // "Premium"
var i3e6116c5_expr_20 = global::System.Linq.Expressions.Expression.Condition(i3e6116c5_expr_17, i3e6116c5_expr_19, i3e6116c5_expr_16, typeof(string));
var i3e6116c5_expr_21 = typeof(T1).GetConstructors()[0];
var i3e6116c5_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6116c5_expr_21, new global::System.Linq.Expressions.Expression[] { i3e6116c5_expr_1, i3e6116c5_expr_2, i3e6116c5_expr_20 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Id"), typeof(T1).GetProperty("Name"), typeof(T1).GetProperty("Grade") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6116c5_expr_0, i3e6116c5_p_o);
return (global::ExpressiveSharp.IExpressiveQueryable<T1>)(object)
global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<T0>)(object)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "XLUkkk++MsGOKw3GbtLwr4QBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_Where_3e61_15_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool> __func)
{
// Source: o => o.Customer?.Email != null
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("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Customer
var i3e6115c5_expr_2 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_expr_1, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Email", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // .Email
var i3e6115c5_expr_4 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer));
var i3e6115c5_expr_5 = global::System.Linq.Expressions.Expression.NotEqual(i3e6115c5_expr_1, i3e6115c5_expr_4);
var i3e6115c5_expr_6 = global::System.Linq.Expressions.Expression.Default(typeof(string));
var i3e6115c5_expr_3 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_5, i3e6115c5_expr_2, i3e6115c5_expr_6, typeof(string));
var i3e6115c5_expr_8 = global::System.Linq.Expressions.Expression.Constant(null, typeof(object)); // null
var i3e6115c5_expr_7 = global::System.Linq.Expressions.Expression.Convert(i3e6115c5_expr_8, typeof(string));
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.NotEqual, i3e6115c5_expr_3, i3e6115c5_expr_7);
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(i3e6115c5_expr_0, i3e6115c5_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Where(
(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
.Where(o => o.Customer?.Email != null)
.Select(o => new
{
o.Id,
Name = o.Customer?.Name ?? "Unknown",
Grade = o.Items.Count() switch
{
>= 10 => "Premium",
>= 5 => "Standard",
_ => "Budget"
}
})
.OrderBy(x => x.Name)Generated SQL:
SELECT "o"."Id", "c"."Name", CASE
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") >= 10 THEN 'Premium'
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId") >= 5 THEN 'Standard'
ELSE 'Budget'
END AS "Grade"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "c"."Email" IS NOT NULL
ORDER BY "c"."Name"The source generator intercepts these calls at compile time and rewrites the delegate lambdas to expression trees. The chain continues as an IExpressiveQueryable<T>, preserving the ability to use modern syntax in subsequent calls.
2. ExpressiveDbSet<T> -- For EF Core
A shorthand for EF Core projects. ExpressiveDbSet<T> wraps a DbSet<T> and provides IExpressiveQueryable<T> behavior automatically:
public class MyDbContext : DbContext
{
// Shorthand for Set<Order>().AsExpressiveDbSet()
public ExpressiveDbSet<Order> Orders => this.ExpressiveSet<Order>();
}db
.Orders
.Where(o => o.Customer?.Email != null)
.Select(o => new
{
o.Id,
Total = o.Total(),
Grade = o.GetGrade()
})
// Setup
public static class OrderDbSetExt
{
[Expressive]
public static decimal Total(this Order o) => o.Items.Sum(i => i.UnitPrice * i.Quantity);
[Expressive]
public static string GetGrade(this Order o) => o.Items.Count() switch
{
>= 10 => "Premium",
>= 5 => "Standard",
_ => "Budget"
};
}SELECT "o"."Id", (
SELECT COALESCE(ef_sum(ef_multiply("l"."UnitPrice", CAST("l"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") AS "Total", CASE
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId") >= 10 THEN 'Premium'
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l1"
WHERE "o"."Id" = "l1"."OrderId") >= 5 THEN 'Standard'
ELSE 'Budget'
END AS "Grade"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "c"."Email" IS NOT NULLSELECT o."Id", (
SELECT COALESCE(sum(l."UnitPrice" * l."Quantity"::numeric(18,2)), 0.0)
FROM "LineItems" AS l
WHERE o."Id" = l."OrderId") AS "Total", CASE
WHEN (
SELECT count(*)::int
FROM "LineItems" AS l0
WHERE o."Id" = l0."OrderId") >= 10 THEN 'Premium'
WHEN (
SELECT count(*)::int
FROM "LineItems" AS l1
WHERE o."Id" = l1."OrderId") >= 5 THEN 'Standard'
ELSE 'Budget'
END AS "Grade"
FROM "Orders" AS o
INNER JOIN "Customers" AS c ON o."CustomerId" = c."Id"
WHERE c."Email" IS NOT NULLSELECT [o].[Id], (
SELECT COALESCE(SUM([l].[UnitPrice] * CAST([l].[Quantity] AS decimal(18,2))), 0.0)
FROM [LineItems] AS [l]
WHERE [o].[Id] = [l].[OrderId]) AS [Total], CASE
WHEN (
SELECT COUNT(*)
FROM [LineItems] AS [l0]
WHERE [o].[Id] = [l0].[OrderId]) >= 10 THEN N'Premium'
WHEN (
SELECT COUNT(*)
FROM [LineItems] AS [l1]
WHERE [o].[Id] = [l1].[OrderId]) >= 5 THEN N'Standard'
ELSE N'Budget'
END AS [Grade]
FROM [Orders] AS [o]
INNER JOIN [Customers] AS [c] ON [o].[CustomerId] = [c].[Id]
WHERE [c].[Email] IS NOT NULLplayground.orders.Aggregate([
{
"$match" : {
"Customer.Email" : { "$ne" : null }
}
},
{
"$project" : {
"_id" : "$_id",
"Total" : {
"$sum" : {
"$map" : {
"input" : "$Items",
"as" : "i",
"in" : {
"$multiply" : ["$$i.UnitPrice", "$$i.Quantity"]
}
}
}
},
"Grade" : {
"$cond" : {
"if" : {
"$gte" : [
{ "$size" : "$Items" },
10
]
},
"then" : "Premium",
"else" : {
"$cond" : {
"if" : {
"$gte" : [
{ "$size" : "$Items" },
5
]
},
"then" : "Standard",
"else" : "Budget"
}
}
}
}
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderDbSetExt.Total_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_OrderDbSetExt
{
// [Expressive]
// public static decimal Total(this Order o) => o.Items.Sum(i => i.UnitPrice * i.Quantity);
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, decimal>> Total_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 p_i_2 = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem), "i"); // i => i.UnitPrice * i.Quantity
var expr_4 = global::System.Linq.Expressions.Expression.Property(p_i_2, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem).GetProperty("UnitPrice", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // i.UnitPrice
var expr_6 = global::System.Linq.Expressions.Expression.Property(p_i_2, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem).GetProperty("Quantity", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // i.Quantity
var expr_5 = global::System.Linq.Expressions.Expression.Convert(expr_6, typeof(decimal));
var expr_3 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Multiply, expr_4, expr_5);
var expr_7 = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem, decimal>>(expr_3, p_i_2);
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 == "Sum" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 2 && m.GetParameters()[0].ParameterType.IsGenericType && !m.GetParameters()[0].ParameterType.IsGenericParameter && m.GetParameters()[1].ParameterType.IsGenericType && !m.GetParameters()[1].ParameterType.IsGenericParameter && m.GetParameters()[1].ParameterType.GetGenericArguments()[1] == typeof(decimal))).MakeGenericMethod(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem)), new global::System.Linq.Expressions.Expression[] { expr_1, expr_7 });
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, decimal>>(expr_0, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderDbSetExt.GetGrade_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_OrderDbSetExt
{
// [Expressive]
// public static string GetGrade(this Order o) => o.Items.Count() switch
// {
// >= 10 => "Premium",
// >= 5 => "Standard",
// _ => "Budget"
// };
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string>> GetGrade_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 });
var expr_2 = global::System.Linq.Expressions.Expression.Constant("Budget", typeof(string)); // "Budget"
var expr_4 = global::System.Linq.Expressions.Expression.Constant(5, typeof(int)); // 5
var expr_3 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_4);
var expr_5 = global::System.Linq.Expressions.Expression.Constant("Standard", typeof(string)); // "Standard"
var expr_6 = global::System.Linq.Expressions.Expression.Condition(expr_3, expr_5, expr_2, typeof(string));
var expr_8 = global::System.Linq.Expressions.Expression.Constant(10, typeof(int)); // 10
var expr_7 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_8);
var expr_9 = global::System.Linq.Expressions.Expression.Constant("Premium", typeof(string)); // "Premium"
var expr_10 = global::System.Linq.Expressions.Expression.Condition(expr_7, expr_9, expr_6, typeof(string));
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string>>(expr_10, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderDbSetExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderDbSetExt { }
}
// === 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.OrderDbSetExt).GetMethod("Total", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderDbSetExt", "Total_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDbSetExt).GetMethod("GetGrade", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderDbSetExt", "GetGrade_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_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, "nWLUY92/0eSK9OuuHwdk4a8BAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T1> __Polyfill_Select_3e61_16_5<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: o => new { o.Id, Total = o.Total(), Grade = o.GetGrade() }
var i3e6116c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "o");
var i3e6116c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_o, typeof(T0).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var i3e6116c5_expr_2 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDbSetExt).GetMethod("Total", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(T0) }, null), new global::System.Linq.Expressions.Expression[] { i3e6116c5_p_o }); // o.Total()
var i3e6116c5_expr_3 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderDbSetExt).GetMethod("GetGrade", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(T0) }, null), new global::System.Linq.Expressions.Expression[] { i3e6116c5_p_o }); // o.GetGrade()
var i3e6116c5_expr_4 = typeof(T1).GetConstructors()[0];
var i3e6116c5_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6116c5_expr_4, new global::System.Linq.Expressions.Expression[] { i3e6116c5_expr_1, i3e6116c5_expr_2, i3e6116c5_expr_3 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Id"), typeof(T1).GetProperty("Total"), typeof(T1).GetProperty("Grade") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6116c5_expr_0, i3e6116c5_p_o);
return (global::ExpressiveSharp.IExpressiveQueryable<T1>)(object)
global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<T0>)(object)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "nWLUY92/0eSK9OuuHwdk4YQBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_Where_3e61_15_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool> __func)
{
// Source: o => o.Customer?.Email != null
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("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Customer
var i3e6115c5_expr_2 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_expr_1, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Email", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // .Email
var i3e6115c5_expr_4 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer));
var i3e6115c5_expr_5 = global::System.Linq.Expressions.Expression.NotEqual(i3e6115c5_expr_1, i3e6115c5_expr_4);
var i3e6115c5_expr_6 = global::System.Linq.Expressions.Expression.Default(typeof(string));
var i3e6115c5_expr_3 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_5, i3e6115c5_expr_2, i3e6115c5_expr_6, typeof(string));
var i3e6115c5_expr_8 = global::System.Linq.Expressions.Expression.Constant(null, typeof(object)); // null
var i3e6115c5_expr_7 = global::System.Linq.Expressions.Expression.Convert(i3e6115c5_expr_8, typeof(string));
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.NotEqual, i3e6115c5_expr_3, i3e6115c5_expr_7);
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(i3e6115c5_expr_0, i3e6115c5_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Where(
(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
.Where(o => o.Customer?.Email != null)
.Select(o => new
{
o.Id,
Total = o.Total(),
Grade = o.GetGrade()
})
// Setup
public static class OrderDbSetExt
{
[Expressive]
public static decimal Total(this Order o) => o.Items.Sum(i => i.UnitPrice * i.Quantity);
[Expressive]
public static string GetGrade(this Order o) => o.Items.Count() switch
{
>= 10 => "Premium",
>= 5 => "Standard",
_ => "Budget"
};
}Generated SQL:
SELECT "o"."Id", (
SELECT COALESCE(ef_sum(ef_multiply("l"."UnitPrice", CAST("l"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") AS "Total", CASE
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId") >= 10 THEN 'Premium'
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l1"
WHERE "o"."Id" = "l1"."OrderId") >= 5 THEN 'Standard'
ELSE 'Budget'
END AS "Grade"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "c"."Email" IS NOT NULLExpressiveDbSet<T> also preserves chain continuity for EF Core-specific operations:
var result = await ctx.Orders
.Include(o => o.Customer)
.AsNoTracking()
.Where(o => o.Customer?.Name == "Alice")
.FirstOrDefaultAsync(o => o.Items.Count() > 3);3. ExpressionPolyfill.Create -- For Standalone Expression Trees
When you need an Expression<TDelegate> without a queryable at all:
// Returns Expression<Func<Order, int?>> -- intercepted at compile time
var expr = ExpressionPolyfill.Create((Order o) => o.Customer?.Name!.Length);
// With transformers
var expr2 = ExpressionPolyfill.Create(
(Order o) => o.Customer?.Email,
new RemoveNullConditionalPatterns());This is useful for building expression trees that you pass to other APIs, or for testing.
Practical Examples
Null-Conditional in Where
db
.Orders
.Where(o => o.Customer?.Email != null)
.Where(o => o.Customer?.Country == "US")SELECT "o"."Id", "o"."CustomerId", "o"."PlacedAt", "o"."Status"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "c"."Email" IS NOT NULL AND "c"."Country" = 'US'SELECT o."Id", o."CustomerId", o."PlacedAt", o."Status"
FROM "Orders" AS o
INNER JOIN "Customers" AS c ON o."CustomerId" = c."Id"
WHERE c."Email" IS NOT NULL AND c."Country" = 'US'SELECT [o].[Id], [o].[CustomerId], [o].[PlacedAt], [o].[Status]
FROM [Orders] AS [o]
INNER JOIN [Customers] AS [c] ON [o].[CustomerId] = [c].[Id]
WHERE [c].[Email] IS NOT NULL AND [c].[Country] = N'US'playground.orders.Aggregate([
{
"$match" : {
"Customer.Email" : { "$ne" : null }
}
},
{
"$match" : { "Customer.Country" : "US" }
}
])// === PolyfillInterceptors_b1293e61.g.cs ===
// <auto-generated/>
#nullable disable
namespace ExpressiveSharp.Generated.Interceptors
{
internal static partial class PolyfillInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "0zhHsAzguQCKakI4naP4Eq8BAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_Where_3e61_16_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool> __func)
{
// Source: o => o.Customer?.Country == "US"
var i3e6116c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6116c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_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 i3e6116c5_expr_2 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_expr_1, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Country", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // .Country
var i3e6116c5_expr_4 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer));
var i3e6116c5_expr_5 = global::System.Linq.Expressions.Expression.NotEqual(i3e6116c5_expr_1, i3e6116c5_expr_4);
var i3e6116c5_expr_6 = global::System.Linq.Expressions.Expression.Default(typeof(string));
var i3e6116c5_expr_3 = global::System.Linq.Expressions.Expression.Condition(i3e6116c5_expr_5, i3e6116c5_expr_2, i3e6116c5_expr_6, typeof(string));
var i3e6116c5_expr_7 = global::System.Linq.Expressions.Expression.Constant("US", typeof(string)); // "US"
var i3e6116c5_expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Equal, i3e6116c5_expr_3, i3e6116c5_expr_7);
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(i3e6116c5_expr_0, i3e6116c5_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Where(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "0zhHsAzguQCKakI4naP4EoQBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_Where_3e61_15_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool> __func)
{
// Source: o => o.Customer?.Email != null
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("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Customer
var i3e6115c5_expr_2 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_expr_1, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Email", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // .Email
var i3e6115c5_expr_4 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer));
var i3e6115c5_expr_5 = global::System.Linq.Expressions.Expression.NotEqual(i3e6115c5_expr_1, i3e6115c5_expr_4);
var i3e6115c5_expr_6 = global::System.Linq.Expressions.Expression.Default(typeof(string));
var i3e6115c5_expr_3 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_5, i3e6115c5_expr_2, i3e6115c5_expr_6, typeof(string));
var i3e6115c5_expr_8 = global::System.Linq.Expressions.Expression.Constant(null, typeof(object)); // null
var i3e6115c5_expr_7 = global::System.Linq.Expressions.Expression.Convert(i3e6115c5_expr_8, typeof(string));
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.NotEqual, i3e6115c5_expr_3, i3e6115c5_expr_7);
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(i3e6115c5_expr_0, i3e6115c5_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Where(
(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
.Where(o => o.Customer?.Email != null)
.Where(o => o.Customer?.Country == "US")Generated SQL:
SELECT "o"."Id", "o"."CustomerId", "o"."PlacedAt", "o"."Status"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "c"."Email" IS NOT NULL AND "c"."Country" = 'US'Switch Expressions in Select
db
.Orders
.Select(o => new
{
o.Id,
Tier = o.Items.Count() switch
{
>= 10 => "Premium",
>= 5 => "Standard",
_ => "Budget"
},
Priority = o.Status switch
{
OrderStatus.Pending => "Urgent",
OrderStatus.Paid => "Normal",
_ => "Low"
}
}).param set @Pending 0
.param set @Paid 1
SELECT "o"."Id", CASE
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") >= 10 THEN 'Premium'
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId") >= 5 THEN 'Standard'
ELSE 'Budget'
END AS "Tier", CASE
WHEN "o"."Status" = @Pending THEN 'Urgent'
WHEN "o"."Status" = @Paid THEN 'Normal'
ELSE 'Low'
END AS "Priority"
FROM "Orders" AS "o"-- @Pending='0'
-- @Paid='1'
SELECT o."Id", CASE
WHEN (
SELECT count(*)::int
FROM "LineItems" AS l
WHERE o."Id" = l."OrderId") >= 10 THEN 'Premium'
WHEN (
SELECT count(*)::int
FROM "LineItems" AS l0
WHERE o."Id" = l0."OrderId") >= 5 THEN 'Standard'
ELSE 'Budget'
END AS "Tier", CASE
WHEN o."Status" = @Pending THEN 'Urgent'
WHEN o."Status" = @Paid THEN 'Normal'
ELSE 'Low'
END AS "Priority"
FROM "Orders" AS oDECLARE @Pending int = 0;
DECLARE @Paid int = 1;
SELECT [o].[Id], CASE
WHEN (
SELECT COUNT(*)
FROM [LineItems] AS [l]
WHERE [o].[Id] = [l].[OrderId]) >= 10 THEN N'Premium'
WHEN (
SELECT COUNT(*)
FROM [LineItems] AS [l0]
WHERE [o].[Id] = [l0].[OrderId]) >= 5 THEN N'Standard'
ELSE N'Budget'
END AS [Tier], CASE
WHEN [o].[Status] = @Pending THEN N'Urgent'
WHEN [o].[Status] = @Paid THEN N'Normal'
ELSE N'Low'
END AS [Priority]
FROM [Orders] AS [o]playground.orders.Aggregate([
{
"$project" : {
"_id" : "$_id",
"Tier" : {
"$cond" : {
"if" : {
"$gte" : [
{ "$size" : "$Items" },
10
]
},
"then" : "Premium",
"else" : {
"$cond" : {
"if" : {
"$gte" : [
{ "$size" : "$Items" },
5
]
},
"then" : "Standard",
"else" : "Budget"
}
}
}
},
"Priority" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 0]
},
"then" : "Urgent",
"else" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 1]
},
"then" : "Normal",
"else" : "Low"
}
}
}
}
}
}
])// === PolyfillInterceptors_b1293e61.g.cs ===
// <auto-generated/>
#nullable disable
namespace ExpressiveSharp.Generated.Interceptors
{
internal static partial class PolyfillInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "ER2sUDaDejayQF6kgwFitYQBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T1> __Polyfill_Select_3e61_15_5<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: o => new { o.Id, Tier = o.Items.Count() switch { >= 10 => "Premium", >= 5 => "Standard", _ => "Budget" }, Priority = o.Status switch { OrderStatus.Pending => "Urgent", OrderStatus.Paid => "Normal", _ => "Low" } }
var i3e6115c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "o");
var i3e6115c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_p_o, typeof(T0).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var i3e6115c5_expr_3 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_p_o, typeof(T0).GetProperty("Items", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Items
var i3e6115c5_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[] { i3e6115c5_expr_3 });
var i3e6115c5_expr_4 = global::System.Linq.Expressions.Expression.Constant("Budget", typeof(string)); // "Budget"
var i3e6115c5_expr_6 = global::System.Linq.Expressions.Expression.Constant(5, typeof(int)); // 5
var i3e6115c5_expr_5 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, i3e6115c5_expr_2, i3e6115c5_expr_6);
var i3e6115c5_expr_7 = global::System.Linq.Expressions.Expression.Constant("Standard", typeof(string)); // "Standard"
var i3e6115c5_expr_8 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_5, i3e6115c5_expr_7, i3e6115c5_expr_4, typeof(string));
var i3e6115c5_expr_10 = global::System.Linq.Expressions.Expression.Constant(10, typeof(int)); // 10
var i3e6115c5_expr_9 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, i3e6115c5_expr_2, i3e6115c5_expr_10);
var i3e6115c5_expr_11 = global::System.Linq.Expressions.Expression.Constant("Premium", typeof(string)); // "Premium"
var i3e6115c5_expr_12 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_9, i3e6115c5_expr_11, i3e6115c5_expr_8, typeof(string));
var i3e6115c5_expr_13 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_p_o, typeof(T0).GetProperty("Status", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Status
var i3e6115c5_expr_14 = global::System.Linq.Expressions.Expression.Constant("Low", typeof(string)); // "Low"
var i3e6115c5_expr_16 = global::System.Linq.Expressions.Expression.Field(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus).GetField("Paid", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static)); // OrderStatus.Paid
var i3e6115c5_expr_15 = global::System.Linq.Expressions.Expression.Equal(i3e6115c5_expr_13, i3e6115c5_expr_16);
var i3e6115c5_expr_17 = global::System.Linq.Expressions.Expression.Constant("Normal", typeof(string)); // "Normal"
var i3e6115c5_expr_18 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_15, i3e6115c5_expr_17, i3e6115c5_expr_14, typeof(string));
var i3e6115c5_expr_20 = global::System.Linq.Expressions.Expression.Field(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus).GetField("Pending", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static)); // OrderStatus.Pending
var i3e6115c5_expr_19 = global::System.Linq.Expressions.Expression.Equal(i3e6115c5_expr_13, i3e6115c5_expr_20);
var i3e6115c5_expr_21 = global::System.Linq.Expressions.Expression.Constant("Urgent", typeof(string)); // "Urgent"
var i3e6115c5_expr_22 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_19, i3e6115c5_expr_21, i3e6115c5_expr_18, typeof(string));
var i3e6115c5_expr_23 = typeof(T1).GetConstructors()[0];
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6115c5_expr_23, new global::System.Linq.Expressions.Expression[] { i3e6115c5_expr_1, i3e6115c5_expr_12, i3e6115c5_expr_22 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Id"), typeof(T1).GetProperty("Tier"), typeof(T1).GetProperty("Priority") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6115c5_expr_0, i3e6115c5_p_o);
return (global::ExpressiveSharp.IExpressiveQueryable<T1>)(object)
global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<T0>)(object)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
{
o.Id,
Tier = o.Items.Count() switch
{
>= 10 => "Premium",
>= 5 => "Standard",
_ => "Budget"
},
Priority = o.Status switch
{
OrderStatus.Pending => "Urgent",
OrderStatus.Paid => "Normal",
_ => "Low"
}
})Generated SQL:
.param set @Pending 0
.param set @Paid 1
SELECT "o"."Id", CASE
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") >= 10 THEN 'Premium'
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId") >= 5 THEN 'Standard'
ELSE 'Budget'
END AS "Tier", CASE
WHEN "o"."Status" = @Pending THEN 'Urgent'
WHEN "o"."Status" = @Paid THEN 'Normal'
ELSE 'Low'
END AS "Priority"
FROM "Orders" AS "o"Pattern Matching in OrderBy
db
.Orders
.OrderBy(o => o.Items.Count() switch
{
>= 10 => 1,
>= 5 => 2,
_ => 3
})
.ThenBy(o => o.Customer!.Name ?? "ZZZ")SELECT "o"."Id", "o"."CustomerId", "o"."PlacedAt", "o"."Status"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
ORDER BY CASE
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") >= 10 THEN 1
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId") >= 5 THEN 2
ELSE 3
END, "c"."Name"SELECT o."Id", o."CustomerId", o."PlacedAt", o."Status"
FROM "Orders" AS o
INNER JOIN "Customers" AS c ON o."CustomerId" = c."Id"
ORDER BY CASE
WHEN (
SELECT count(*)::int
FROM "LineItems" AS l
WHERE o."Id" = l."OrderId") >= 10 THEN 1
WHEN (
SELECT count(*)::int
FROM "LineItems" AS l0
WHERE o."Id" = l0."OrderId") >= 5 THEN 2
ELSE 3
END, c."Name"SELECT [o].[Id], [o].[CustomerId], [o].[PlacedAt], [o].[Status]
FROM [Orders] AS [o]
INNER JOIN [Customers] AS [c] ON [o].[CustomerId] = [c].[Id]
ORDER BY CASE
WHEN (
SELECT COUNT(*)
FROM [LineItems] AS [l]
WHERE [o].[Id] = [l].[OrderId]) >= 10 THEN 1
WHEN (
SELECT COUNT(*)
FROM [LineItems] AS [l0]
WHERE [o].[Id] = [l0].[OrderId]) >= 5 THEN 2
ELSE 3
END, [c].[Name]playground.orders.Aggregate([
{
"$project" : {
"_id" : 0,
"_document" : "$$ROOT",
"_key1" : {
"$cond" : {
"if" : {
"$gte" : [
{ "$size" : "$Items" },
10
]
},
"then" : 1,
"else" : {
"$cond" : {
"if" : {
"$gte" : [
{ "$size" : "$Items" },
5
]
},
"then" : 2,
"else" : 3
}
}
}
},
"_key2" : {
"$ifNull" : ["$Customer.Name", "ZZZ"]
}
}
},
{
"$sort" : { "_key1" : 1, "_key2" : 1 }
},
{
"$replaceRoot" : { "newRoot" : "$_document" }
}
])// === PolyfillInterceptors_b1293e61.g.cs ===
// <auto-generated/>
#nullable disable
namespace ExpressiveSharp.Generated.Interceptors
{
internal static partial class PolyfillInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "vwXIlJbh1aZCCF3QOXFlM/UBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_ThenBy_3e61_21_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string> __func)
{
// Source: o => o.Customer!.Name ?? "ZZZ"
var i3e6121c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6121c5_expr_2 = global::System.Linq.Expressions.Expression.Property(i3e6121c5_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 i3e6121c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6121c5_expr_2, 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 i3e6121c5_expr_3 = global::System.Linq.Expressions.Expression.Constant("ZZZ", typeof(string)); // "ZZZ"
var i3e6121c5_expr_0 = global::System.Linq.Expressions.Expression.Coalesce(i3e6121c5_expr_1, i3e6121c5_expr_3);
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string>>(i3e6121c5_expr_0, i3e6121c5_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.ThenBy(
(global::System.Linq.IOrderedQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "vwXIlJbh1aZCCF3QOXFlM4QBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_OrderBy_3e61_15_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, int> __func)
{
// Source: o => o.Items.Count() switch { >= 10 => 1, >= 5 => 2, _ => 3 }
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("Items", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Items
var i3e6115c5_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[] { i3e6115c5_expr_1 });
var i3e6115c5_expr_2 = global::System.Linq.Expressions.Expression.Constant(3, typeof(int)); // 3
var i3e6115c5_expr_4 = global::System.Linq.Expressions.Expression.Constant(5, typeof(int)); // 5
var i3e6115c5_expr_3 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, i3e6115c5_expr_0, i3e6115c5_expr_4);
var i3e6115c5_expr_5 = global::System.Linq.Expressions.Expression.Constant(2, typeof(int)); // 2
var i3e6115c5_expr_6 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_3, i3e6115c5_expr_5, i3e6115c5_expr_2, typeof(int));
var i3e6115c5_expr_8 = global::System.Linq.Expressions.Expression.Constant(10, typeof(int)); // 10
var i3e6115c5_expr_7 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, i3e6115c5_expr_0, i3e6115c5_expr_8);
var i3e6115c5_expr_9 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var i3e6115c5_expr_10 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_7, i3e6115c5_expr_9, i3e6115c5_expr_6, typeof(int));
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, int>>(i3e6115c5_expr_10, i3e6115c5_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.OrderBy(
(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
.OrderBy(o => o.Items.Count() switch
{
>= 10 => 1,
>= 5 => 2,
_ => 3
})
.ThenBy(o => o.Customer!.Name ?? "ZZZ")Generated SQL:
SELECT "o"."Id", "o"."CustomerId", "o"."PlacedAt", "o"."Status"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
ORDER BY CASE
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") >= 10 THEN 1
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId") >= 5 THEN 2
ELSE 3
END, "c"."Name"Combining [Expressive] Members with Inline Modern Syntax
The two approaches compose naturally. [Expressive] members are expanded, and inline modern syntax is rewritten, all in the same query:
db
.Orders
.Where(o => o.IsRecent() && o.Customer!.Country == "US")
.Select(o => new
{
o.Id,
Total = o.Total(), // [Expressive] method
CustomerEmail = o.CustomerEmail(), // [Expressive] method with ?.
Tier = o.Total() switch // inline switch on [Expressive] result
{
>= 1000m => "Premium",
>= 250m => "Standard",
_ => "Basic"
}
})
// Setup
public static class OrderCombinedExt
{
[Expressive]
public static bool IsRecent(this Order o) => o.PlacedAt >= new DateTime(2024, 1, 1);
[Expressive]
public static decimal Total(this Order o) => o.Items.Sum(i => i.UnitPrice * i.Quantity);
[Expressive]
public static string? CustomerEmail(this Order o) => o.Customer?.Email;
}SELECT "o"."Id", (
SELECT COALESCE(ef_sum(ef_multiply("l"."UnitPrice", CAST("l"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") AS "Total", "c"."Email" AS "CustomerEmail", CASE
WHEN ef_compare((
SELECT COALESCE(ef_sum(ef_multiply("l0"."UnitPrice", CAST("l0"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId"), '1000.0') >= 0 THEN 'Premium'
WHEN ef_compare((
SELECT COALESCE(ef_sum(ef_multiply("l1"."UnitPrice", CAST("l1"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l1"
WHERE "o"."Id" = "l1"."OrderId"), '250.0') >= 0 THEN 'Standard'
ELSE 'Basic'
END AS "Tier"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "o"."PlacedAt" >= '2024-01-01 00:00:00' AND "c"."Country" = 'US'SELECT o."Id", (
SELECT COALESCE(sum(l."UnitPrice" * l."Quantity"::numeric(18,2)), 0.0)
FROM "LineItems" AS l
WHERE o."Id" = l."OrderId") AS "Total", c."Email" AS "CustomerEmail", CASE
WHEN (
SELECT COALESCE(sum(l0."UnitPrice" * l0."Quantity"::numeric(18,2)), 0.0)
FROM "LineItems" AS l0
WHERE o."Id" = l0."OrderId") >= 1000.0 THEN 'Premium'
WHEN (
SELECT COALESCE(sum(l1."UnitPrice" * l1."Quantity"::numeric(18,2)), 0.0)
FROM "LineItems" AS l1
WHERE o."Id" = l1."OrderId") >= 250.0 THEN 'Standard'
ELSE 'Basic'
END AS "Tier"
FROM "Orders" AS o
INNER JOIN "Customers" AS c ON o."CustomerId" = c."Id"
WHERE o."PlacedAt" >= TIMESTAMP '2024-01-01T00:00:00' AND c."Country" = 'US'SELECT [o].[Id], (
SELECT COALESCE(SUM([l].[UnitPrice] * CAST([l].[Quantity] AS decimal(18,2))), 0.0)
FROM [LineItems] AS [l]
WHERE [o].[Id] = [l].[OrderId]) AS [Total], [c].[Email] AS [CustomerEmail], CASE
WHEN (
SELECT COALESCE(SUM([l0].[UnitPrice] * CAST([l0].[Quantity] AS decimal(18,2))), 0.0)
FROM [LineItems] AS [l0]
WHERE [o].[Id] = [l0].[OrderId]) >= 1000.0 THEN N'Premium'
WHEN (
SELECT COALESCE(SUM([l1].[UnitPrice] * CAST([l1].[Quantity] AS decimal(18,2))), 0.0)
FROM [LineItems] AS [l1]
WHERE [o].[Id] = [l1].[OrderId]) >= 250.0 THEN N'Standard'
ELSE N'Basic'
END AS [Tier]
FROM [Orders] AS [o]
INNER JOIN [Customers] AS [c] ON [o].[CustomerId] = [c].[Id]
WHERE [o].[PlacedAt] >= '2024-01-01T00:00:00.0000000' AND [c].[Country] = N'US'playground.orders.Aggregate([
{
"$match" : {
"PlacedAt" : {
"$gte" : { "$date" : "2024-01-01T00:00:00Z" }
},
"Customer.Country" : "US"
}
},
{
"$project" : {
"_id" : "$_id",
"Total" : {
"$sum" : {
"$map" : {
"input" : "$Items",
"as" : "i",
"in" : {
"$multiply" : ["$$i.UnitPrice", "$$i.Quantity"]
}
}
}
},
"CustomerEmail" : "$Customer.Email",
"Tier" : {
"$cond" : {
"if" : {
"$gte" : [
{
"$sum" : {
"$map" : {
"input" : "$Items",
"as" : "i",
"in" : {
"$multiply" : ["$$i.UnitPrice", "$$i.Quantity"]
}
}
}
},
{ "$numberDecimal" : "1000" }
]
},
"then" : "Premium",
"else" : {
"$cond" : {
"if" : {
"$gte" : [
{
"$sum" : {
"$map" : {
"input" : "$Items",
"as" : "i",
"in" : {
"$multiply" : ["$$i.UnitPrice", "$$i.Quantity"]
}
}
}
},
{ "$numberDecimal" : "250" }
]
},
"then" : "Standard",
"else" : "Basic"
}
}
}
}
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderCombinedExt.IsRecent_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_OrderCombinedExt
{
// [Expressive]
// public static bool IsRecent(this Order o) => o.PlacedAt >= new DateTime(2024, 1, 1);
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>> IsRecent_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("PlacedAt", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.PlacedAt
var expr_3 = global::System.Linq.Expressions.Expression.Constant(2024, typeof(int)); // 2024
var expr_4 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var expr_5 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var expr_2 = global::System.Linq.Expressions.Expression.New(typeof(global::System.DateTime).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(int), typeof(int), typeof(int) }, null), expr_3, expr_4, expr_5);
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_1, expr_2, false, typeof(global::System.DateTime).GetMethod("op_GreaterThanOrEqual", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::System.DateTime), typeof(global::System.DateTime) }, null));
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(expr_0, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderCombinedExt.Total_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_OrderCombinedExt
{
// [Expressive]
// public static decimal Total(this Order o) => o.Items.Sum(i => i.UnitPrice * i.Quantity);
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, decimal>> Total_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 p_i_2 = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem), "i"); // i => i.UnitPrice * i.Quantity
var expr_4 = global::System.Linq.Expressions.Expression.Property(p_i_2, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem).GetProperty("UnitPrice", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // i.UnitPrice
var expr_6 = global::System.Linq.Expressions.Expression.Property(p_i_2, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem).GetProperty("Quantity", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // i.Quantity
var expr_5 = global::System.Linq.Expressions.Expression.Convert(expr_6, typeof(decimal));
var expr_3 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Multiply, expr_4, expr_5);
var expr_7 = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem, decimal>>(expr_3, p_i_2);
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 == "Sum" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 2 && m.GetParameters()[0].ParameterType.IsGenericType && !m.GetParameters()[0].ParameterType.IsGenericParameter && m.GetParameters()[1].ParameterType.IsGenericType && !m.GetParameters()[1].ParameterType.IsGenericParameter && m.GetParameters()[1].ParameterType.GetGenericArguments()[1] == typeof(decimal))).MakeGenericMethod(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem)), new global::System.Linq.Expressions.Expression[] { expr_1, expr_7 });
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, decimal>>(expr_0, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderCombinedExt.CustomerEmail_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_OrderCombinedExt
{
// [Expressive]
// public static string? CustomerEmail(this Order o) => o.Customer?.Email;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string>> CustomerEmail_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.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_1 = global::System.Linq.Expressions.Expression.Property(expr_0, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Email", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // .Email
var expr_3 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer));
var expr_4 = global::System.Linq.Expressions.Expression.NotEqual(expr_0, expr_3);
var expr_5 = global::System.Linq.Expressions.Expression.Default(typeof(string));
var expr_2 = global::System.Linq.Expressions.Expression.Condition(expr_4, expr_1, expr_5, typeof(string));
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string>>(expr_2, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderCombinedExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderCombinedExt { }
}
// === 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.OrderCombinedExt).GetMethod("IsRecent", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderCombinedExt", "IsRecent_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderCombinedExt).GetMethod("Total", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderCombinedExt", "Total_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderCombinedExt).GetMethod("CustomerEmail", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderCombinedExt", "CustomerEmail_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_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, "3b1r/owrXt+CUMSQ+nJnlMEBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T1> __Polyfill_Select_3e61_16_5<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: o => new { o.Id, Total = o.Total(), // [Expressive] method CustomerEmail = o.CustomerEmail(), // [Expressive] method with ?. Tier = o.Total() switch // inline switch on [Expressive] result { >= 1000m => "Premium", >= 250m => "Standard", _ => "Basic" } }
var i3e6116c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "o");
var i3e6116c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_o, typeof(T0).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var i3e6116c5_expr_2 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderCombinedExt).GetMethod("Total", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(T0) }, null), new global::System.Linq.Expressions.Expression[] { i3e6116c5_p_o }); // o.Total()
var i3e6116c5_expr_3 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderCombinedExt).GetMethod("CustomerEmail", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(T0) }, null), new global::System.Linq.Expressions.Expression[] { i3e6116c5_p_o }); // o.CustomerEmail()
var i3e6116c5_expr_4 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderCombinedExt).GetMethod("Total", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(T0) }, null), new global::System.Linq.Expressions.Expression[] { i3e6116c5_p_o }); // o.Total()
var i3e6116c5_expr_5 = global::System.Linq.Expressions.Expression.Constant("Basic", typeof(string)); // "Basic"
var i3e6116c5_expr_7 = global::System.Linq.Expressions.Expression.Constant(250m, typeof(decimal)); // 250m
var i3e6116c5_expr_6 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, i3e6116c5_expr_4, i3e6116c5_expr_7);
var i3e6116c5_expr_8 = global::System.Linq.Expressions.Expression.Constant("Standard", typeof(string)); // "Standard"
var i3e6116c5_expr_9 = global::System.Linq.Expressions.Expression.Condition(i3e6116c5_expr_6, i3e6116c5_expr_8, i3e6116c5_expr_5, typeof(string));
var i3e6116c5_expr_11 = global::System.Linq.Expressions.Expression.Constant(1000m, typeof(decimal)); // 1000m
var i3e6116c5_expr_10 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, i3e6116c5_expr_4, i3e6116c5_expr_11);
var i3e6116c5_expr_12 = global::System.Linq.Expressions.Expression.Constant("Premium", typeof(string)); // "Premium"
var i3e6116c5_expr_13 = global::System.Linq.Expressions.Expression.Condition(i3e6116c5_expr_10, i3e6116c5_expr_12, i3e6116c5_expr_9, typeof(string));
var i3e6116c5_expr_14 = typeof(T1).GetConstructors()[0];
var i3e6116c5_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6116c5_expr_14, new global::System.Linq.Expressions.Expression[] { i3e6116c5_expr_1, i3e6116c5_expr_2, i3e6116c5_expr_3, i3e6116c5_expr_13 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Id"), typeof(T1).GetProperty("Total"), typeof(T1).GetProperty("CustomerEmail"), typeof(T1).GetProperty("Tier") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6116c5_expr_0, i3e6116c5_p_o);
return (global::ExpressiveSharp.IExpressiveQueryable<T1>)(object)
global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<T0>)(object)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "3b1r/owrXt+CUMSQ+nJnlIQBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_Where_3e61_15_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool> __func)
{
// Source: o => o.IsRecent() && o.Customer!.Country == "US"
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.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderCombinedExt).GetMethod("IsRecent", 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.IsRecent()
var i3e6115c5_expr_4 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_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 i3e6115c5_expr_3 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_expr_4, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Country", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var i3e6115c5_expr_5 = global::System.Linq.Expressions.Expression.Constant("US", typeof(string)); // "US"
var i3e6115c5_expr_2 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Equal, i3e6115c5_expr_3, i3e6115c5_expr_5);
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.AndAlso, i3e6115c5_expr_1, i3e6115c5_expr_2);
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(i3e6115c5_expr_0, i3e6115c5_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Where(
(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
.Where(o => o.IsRecent() && o.Customer!.Country == "US")
.Select(o => new
{
o.Id,
Total = o.Total(), // [Expressive] method
CustomerEmail = o.CustomerEmail(), // [Expressive] method with ?.
Tier = o.Total() switch // inline switch on [Expressive] result
{
>= 1000m => "Premium",
>= 250m => "Standard",
_ => "Basic"
}
})
// Setup
public static class OrderCombinedExt
{
[Expressive]
public static bool IsRecent(this Order o) => o.PlacedAt >= new DateTime(2024, 1, 1);
[Expressive]
public static decimal Total(this Order o) => o.Items.Sum(i => i.UnitPrice * i.Quantity);
[Expressive]
public static string? CustomerEmail(this Order o) => o.Customer?.Email;
}Generated SQL:
SELECT "o"."Id", (
SELECT COALESCE(ef_sum(ef_multiply("l"."UnitPrice", CAST("l"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") AS "Total", "c"."Email" AS "CustomerEmail", CASE
WHEN ef_compare((
SELECT COALESCE(ef_sum(ef_multiply("l0"."UnitPrice", CAST("l0"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId"), '1000.0') >= 0 THEN 'Premium'
WHEN ef_compare((
SELECT COALESCE(ef_sum(ef_multiply("l1"."UnitPrice", CAST("l1"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l1"
WHERE "o"."Id" = "l1"."OrderId"), '250.0') >= 0 THEN 'Standard'
ELSE 'Basic'
END AS "Tier"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "o"."PlacedAt" >= '2024-01-01 00:00:00' AND "c"."Country" = 'US'When to Use Which Approach
| Scenario | Approach |
|---|---|
EF Core project, modern syntax on DbSet | ExpressiveDbSet<T> |
Any IQueryable, modern syntax in chains | .AsExpressive() |
| Standalone expression tree, no queryable | ExpressionPolyfill.Create |
| Reusable logic across multiple queries | [Expressive] property or method |
| One-off query logic, not reused elsewhere | Inline modern syntax via the above |
Combine both approaches
Use [Expressive] for shared business logic (computed properties, filters, classifications) and inline modern syntax for query-specific projections and conditions. They complement each other.
Available LINQ Methods
IExpressiveQueryable<T> and ExpressiveDbSet<T> support most standard Queryable methods:
Filtering: Where, Any, All, Contains
Projection: Select, SelectMany
Ordering: OrderBy, OrderByDescending, ThenBy, ThenByDescending
Grouping: GroupBy
Joins: Join, GroupJoin, Zip
Aggregation: Sum, Average, Min, Max, Count, LongCount
Element access: First, FirstOrDefault, Single, SingleOrDefault, Last, LastOrDefault, ElementAt, ElementAtOrDefault
Set operations: ExceptBy, IntersectBy, UnionBy, DistinctBy
Non-lambda (chain-preserving): Take, Skip, Distinct, Reverse, Append, Prepend, DefaultIfEmpty, Concat, Union, Intersect, Except
EF Core (ExpressiveDbSet only): Include, ThenInclude, AsNoTracking, IgnoreQueryFilters, TagWith, AnyAsync, FirstAsync, SumAsync, and all other async lambda methods
On .NET 9+, CountBy, AggregateBy, and Index are available. On .NET 10+, LeftJoin and RightJoin are also available.
Tips
Interceptor scope
The source generator rewrites calls at their exact call site in your source code. If you pass a delegate to a helper method that internally calls .Where(), the interceptor will not see it. Keep the LINQ chain in the same method where modern syntax is used.
ToQueryString() for debugging
Use .ToQueryString() to inspect the generated query text and verify that your modern syntax is being translated correctly.
See Also
- Nullable Navigation Properties --
?.patterns in depth - Scoring and Classification -- switch expressions and pattern matching
- Computed Entity Properties -- reusable query building blocks
- Window Functions and Ranking -- SQL window functions with ExpressiveDbSet
