Scoring & Classification
This recipe shows how to use C# pattern matching -- switch expressions, is patterns, relational patterns, and more -- inside [Expressive] members to compute scores, tiers, and labels directly in SQL.
Banding with Relational Patterns
Mapping numeric ranges to labels reads naturally as a switch expression and translates to a SQL CASE:
db
.Products
.GroupBy(p => p.PriceBand())
.Select(g => new { Band = g.Key, Count = g.Count() })
.OrderBy(x => x.Band)
// Setup
public static class ProductBand
{
[Expressive]
public static string PriceBand(this Product p) => p.ListPrice switch
{
>= 500m => "A",
>= 200m => "B",
>= 100m => "C",
>= 50m => "D",
_ => "E"
};
[Expressive]
public static bool IsPremium(this Product p) => p.ListPrice >= 500m;
}SELECT "p0"."Key" AS "Band", COUNT(*) AS "Count"
FROM (
SELECT CASE
WHEN ef_compare("p"."ListPrice", '500.0') >= 0 THEN 'A'
WHEN ef_compare("p"."ListPrice", '200.0') >= 0 THEN 'B'
WHEN ef_compare("p"."ListPrice", '100.0') >= 0 THEN 'C'
WHEN ef_compare("p"."ListPrice", '50.0') >= 0 THEN 'D'
ELSE 'E'
END AS "Key"
FROM "Products" AS "p"
) AS "p0"
GROUP BY "p0"."Key"
ORDER BY "p0"."Key"SELECT p0."Key" AS "Band", count(*)::int AS "Count"
FROM (
SELECT CASE
WHEN p."ListPrice" >= 500.0 THEN 'A'
WHEN p."ListPrice" >= 200.0 THEN 'B'
WHEN p."ListPrice" >= 100.0 THEN 'C'
WHEN p."ListPrice" >= 50.0 THEN 'D'
ELSE 'E'
END AS "Key"
FROM "Products" AS p
) AS p0
GROUP BY p0."Key"
ORDER BY p0."Key"SELECT [p0].[Key] AS [Band], COUNT(*) AS [Count]
FROM (
SELECT CASE
WHEN [p].[ListPrice] >= 500.0 THEN N'A'
WHEN [p].[ListPrice] >= 200.0 THEN N'B'
WHEN [p].[ListPrice] >= 100.0 THEN N'C'
WHEN [p].[ListPrice] >= 50.0 THEN N'D'
ELSE N'E'
END AS [Key]
FROM [Products] AS [p]
) AS [p0]
GROUP BY [p0].[Key]
ORDER BY [p0].[Key]playground.products.Aggregate([
{
"$group" : {
"_id" : {
"$cond" : {
"if" : {
"$gte" : [
"$ListPrice",
{ "$numberDecimal" : "500" }
]
},
"then" : "A",
"else" : {
"$cond" : {
"if" : {
"$gte" : [
"$ListPrice",
{ "$numberDecimal" : "200" }
]
},
"then" : "B",
"else" : {
"$cond" : {
"if" : {
"$gte" : [
"$ListPrice",
{ "$numberDecimal" : "100" }
]
},
"then" : "C",
"else" : {
"$cond" : {
"if" : {
"$gte" : [
"$ListPrice",
{ "$numberDecimal" : "50" }
]
},
"then" : "D",
"else" : "E"
}
}
}
}
}
}
}
},
"__agg0" : { "$sum" : 1 }
}
},
{
"$project" : { "Band" : "$_id", "Count" : "$__agg0", "_id" : 0 }
},
{
"$sort" : { "Band" : 1 }
}
])// === ExpressiveSharp_Docs_Playground_Snippet_ProductBand.PriceBand_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_ProductBand
{
// [Expressive]
// public static string PriceBand(this Product p) => p.ListPrice switch
// {
// >= 500m => "A",
// >= 200m => "B",
// >= 100m => "C",
// >= 50m => "D",
// _ => "E"
// };
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string>> PriceBand_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.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_1 = global::System.Linq.Expressions.Expression.Constant("E", typeof(string)); // "E"
var expr_3 = global::System.Linq.Expressions.Expression.Constant(50m, typeof(decimal)); // 50m
var expr_2 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_3);
var expr_4 = global::System.Linq.Expressions.Expression.Constant("D", typeof(string)); // "D"
var expr_5 = global::System.Linq.Expressions.Expression.Condition(expr_2, expr_4, expr_1, typeof(string));
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.GreaterThanOrEqual, expr_0, expr_7);
var expr_8 = global::System.Linq.Expressions.Expression.Constant("C", typeof(string)); // "C"
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(200m, typeof(decimal)); // 200m
var expr_10 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_11);
var expr_12 = global::System.Linq.Expressions.Expression.Constant("B", typeof(string)); // "B"
var expr_13 = global::System.Linq.Expressions.Expression.Condition(expr_10, expr_12, expr_9, typeof(string));
var expr_15 = global::System.Linq.Expressions.Expression.Constant(500m, typeof(decimal)); // 500m
var expr_14 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_15);
var expr_16 = global::System.Linq.Expressions.Expression.Constant("A", typeof(string)); // "A"
var expr_17 = global::System.Linq.Expressions.Expression.Condition(expr_14, expr_16, expr_13, typeof(string));
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string>>(expr_17, p_p);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_ProductBand.IsPremium_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_ProductBand
{
// [Expressive]
// public static bool IsPremium(this Product p) => p.ListPrice >= 500m;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool>> IsPremium_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_1 = 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_2 = global::System.Linq.Expressions.Expression.Constant(500m, typeof(decimal)); // 500m
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_1, expr_2);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool>>(expr_0, p_p);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_ProductBand.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_ProductBand { }
}
// === 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.ProductBand).GetMethod("PriceBand", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_ProductBand", "PriceBand_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Product_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductBand).GetMethod("IsPremium", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_ProductBand", "IsPremium_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, "TvP6g7RMOXE8tmDdj7cZSuEBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T0> __Polyfill_OrderBy_3e61_17_5<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: x => x.Band
var i3e6117c5_p_x = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "x");
var i3e6117c5_expr_0 = global::System.Linq.Expressions.Expression.Property(i3e6117c5_p_x, typeof(T0).GetProperty("Band", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // x.Band
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6117c5_expr_0, i3e6117c5_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, "TvP6g7RMOXE8tmDdj7cZSqcBAABfX1NuaXBwZXQuY3M=")]
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: g => new { Band = g.Key, Count = g.Count() }
var i3e6116c5_p_g = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "g");
var i3e6116c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_g, typeof(T0).GetProperty("Key", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // g.Key
var i3e6116c5_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.Product)), new global::System.Linq.Expressions.Expression[] { i3e6116c5_p_g }); // g.Count()
var i3e6116c5_expr_3 = typeof(T1).GetConstructors()[0];
var i3e6116c5_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6116c5_expr_3, new global::System.Linq.Expressions.Expression[] { i3e6116c5_expr_1, i3e6116c5_expr_2 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Band"), typeof(T1).GetProperty("Count") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6116c5_expr_0, i3e6116c5_p_g);
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, "TvP6g7RMOXE8tmDdj7cZSoYBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::System.Linq.IGrouping<string, global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product>> __Polyfill_GroupBy_3e61_15_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string> __func)
{
// Source: p => p.PriceBand()
var i3e6115c5_p_p = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product), "p");
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductBand).GetMethod("PriceBand", 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.Product) }, null), new global::System.Linq.Expressions.Expression[] { i3e6115c5_p_p }); // p.PriceBand()
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string>>(i3e6115c5_expr_0, i3e6115c5_p_p);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.GroupBy(
(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
.GroupBy(p => p.PriceBand())
.Select(g => new { Band = g.Key, Count = g.Count() })
.OrderBy(x => x.Band)
// Setup
public static class ProductBand
{
[Expressive]
public static string PriceBand(this Product p) => p.ListPrice switch
{
>= 500m => "A",
>= 200m => "B",
>= 100m => "C",
>= 50m => "D",
_ => "E"
};
[Expressive]
public static bool IsPremium(this Product p) => p.ListPrice >= 500m;
}Generated SQL:
SELECT "p0"."Key" AS "Band", COUNT(*) AS "Count"
FROM (
SELECT CASE
WHEN ef_compare("p"."ListPrice", '500.0') >= 0 THEN 'A'
WHEN ef_compare("p"."ListPrice", '200.0') >= 0 THEN 'B'
WHEN ef_compare("p"."ListPrice", '100.0') >= 0 THEN 'C'
WHEN ef_compare("p"."ListPrice", '50.0') >= 0 THEN 'D'
ELSE 'E'
END AS "Key"
FROM "Products" AS "p"
) AS "p0"
GROUP BY "p0"."Key"
ORDER BY "p0"."Key"Customer Tiers with and / or Patterns
Use and and or patterns to express range bands cleanly:
db
.Customers
.GroupBy(c => c.Tier())
.Select(g => new { Tier = g.Key, Count = g.Count() })
// Setup
public static class CustomerTier
{
[Expressive]
public static int OrderCount(this Customer c) => c.Orders.Count();
[Expressive]
public static string Tier(this Customer c) => c.OrderCount() switch
{
>= 50 => "Platinum",
>= 20 and < 50 => "Gold",
>= 5 and < 20 => "Silver",
_ => "Bronze"
};
[Expressive]
public static bool IsLoyalty(this Customer c) => c.OrderCount() >= 10;
}SELECT "c0"."Key" AS "Tier", COUNT(*) AS "Count"
FROM (
SELECT CASE
WHEN (
SELECT COUNT(*)
FROM "Orders" AS "o"
WHERE "c"."Id" = "o"."CustomerId") >= 50 THEN 'Platinum'
WHEN (
SELECT COUNT(*)
FROM "Orders" AS "o0"
WHERE "c"."Id" = "o0"."CustomerId") >= 20 AND (
SELECT COUNT(*)
FROM "Orders" AS "o1"
WHERE "c"."Id" = "o1"."CustomerId") < 50 THEN 'Gold'
WHEN (
SELECT COUNT(*)
FROM "Orders" AS "o2"
WHERE "c"."Id" = "o2"."CustomerId") >= 5 AND (
SELECT COUNT(*)
FROM "Orders" AS "o3"
WHERE "c"."Id" = "o3"."CustomerId") < 20 THEN 'Silver'
ELSE 'Bronze'
END AS "Key"
FROM "Customers" AS "c"
) AS "c0"
GROUP BY "c0"."Key"SELECT c0."Key" AS "Tier", count(*)::int AS "Count"
FROM (
SELECT CASE
WHEN (
SELECT count(*)::int
FROM "Orders" AS o
WHERE c."Id" = o."CustomerId") >= 50 THEN 'Platinum'
WHEN (
SELECT count(*)::int
FROM "Orders" AS o0
WHERE c."Id" = o0."CustomerId") >= 20 AND (
SELECT count(*)::int
FROM "Orders" AS o1
WHERE c."Id" = o1."CustomerId") < 50 THEN 'Gold'
WHEN (
SELECT count(*)::int
FROM "Orders" AS o2
WHERE c."Id" = o2."CustomerId") >= 5 AND (
SELECT count(*)::int
FROM "Orders" AS o3
WHERE c."Id" = o3."CustomerId") < 20 THEN 'Silver'
ELSE 'Bronze'
END AS "Key"
FROM "Customers" AS c
) AS c0
GROUP BY c0."Key"SELECT [c0].[Key] AS [Tier], COUNT(*) AS [Count]
FROM (
SELECT CASE
WHEN (
SELECT COUNT(*)
FROM [Orders] AS [o]
WHERE [c].[Id] = [o].[CustomerId]) >= 50 THEN N'Platinum'
WHEN (
SELECT COUNT(*)
FROM [Orders] AS [o0]
WHERE [c].[Id] = [o0].[CustomerId]) >= 20 AND (
SELECT COUNT(*)
FROM [Orders] AS [o1]
WHERE [c].[Id] = [o1].[CustomerId]) < 50 THEN N'Gold'
WHEN (
SELECT COUNT(*)
FROM [Orders] AS [o2]
WHERE [c].[Id] = [o2].[CustomerId]) >= 5 AND (
SELECT COUNT(*)
FROM [Orders] AS [o3]
WHERE [c].[Id] = [o3].[CustomerId]) < 20 THEN N'Silver'
ELSE N'Bronze'
END AS [Key]
FROM [Customers] AS [c]
) AS [c0]
GROUP BY [c0].[Key]playground.customers.Aggregate([
{
"$group" : {
"_id" : {
"$cond" : {
"if" : {
"$gte" : [
{ "$size" : "$Orders" },
50
]
},
"then" : "Platinum",
"else" : {
"$cond" : {
"if" : {
"$and" : [
{
"$gte" : [
{ "$size" : "$Orders" },
20
]
},
{
"$lt" : [
{ "$size" : "$Orders" },
50
]
}
]
},
"then" : "Gold",
"else" : {
"$cond" : {
"if" : {
"$and" : [
{
"$gte" : [
{ "$size" : "$Orders" },
5
]
},
{
"$lt" : [
{ "$size" : "$Orders" },
20
]
}
]
},
"then" : "Silver",
"else" : "Bronze"
}
}
}
}
}
},
"__agg0" : { "$sum" : 1 }
}
},
{
"$project" : { "Tier" : "$_id", "Count" : "$__agg0", "_id" : 0 }
}
])// === ExpressiveSharp_Docs_Playground_Snippet_CustomerTier.OrderCount_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_CustomerTier
{
// [Expressive]
// public static int OrderCount(this Customer c) => c.Orders.Count();
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, int>> OrderCount_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_1 = 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_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.Order)), new global::System.Linq.Expressions.Expression[] { expr_1 });
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, int>>(expr_0, p_c);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_CustomerTier.Tier_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_CustomerTier
{
// [Expressive]
// public static string Tier(this Customer c) => c.OrderCount() switch
// {
// >= 50 => "Platinum",
// >= 20 and < 50 => "Gold",
// >= 5 and < 20 => "Silver",
// _ => "Bronze"
// };
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, string>> Tier_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.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerTier).GetMethod("OrderCount", 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.Customer) }, null), new global::System.Linq.Expressions.Expression[] { p_c }); // c.OrderCount()
var expr_1 = global::System.Linq.Expressions.Expression.Constant("Bronze", typeof(string)); // "Bronze"
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_6 = global::System.Linq.Expressions.Expression.Constant(20, typeof(int)); // 20
var expr_5 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.LessThan, expr_0, expr_6);
var expr_2 = global::System.Linq.Expressions.Expression.AndAlso(expr_3, expr_5);
var expr_7 = global::System.Linq.Expressions.Expression.Constant("Silver", typeof(string)); // "Silver"
var expr_8 = global::System.Linq.Expressions.Expression.Condition(expr_2, expr_7, expr_1, typeof(string));
var expr_11 = global::System.Linq.Expressions.Expression.Constant(20, typeof(int)); // 20
var expr_10 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_11);
var expr_13 = global::System.Linq.Expressions.Expression.Constant(50, typeof(int)); // 50
var expr_12 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.LessThan, expr_0, expr_13);
var expr_9 = global::System.Linq.Expressions.Expression.AndAlso(expr_10, expr_12);
var expr_14 = global::System.Linq.Expressions.Expression.Constant("Gold", typeof(string)); // "Gold"
var expr_15 = global::System.Linq.Expressions.Expression.Condition(expr_9, expr_14, expr_8, typeof(string));
var expr_17 = global::System.Linq.Expressions.Expression.Constant(50, typeof(int)); // 50
var expr_16 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_17);
var expr_18 = global::System.Linq.Expressions.Expression.Constant("Platinum", typeof(string)); // "Platinum"
var expr_19 = global::System.Linq.Expressions.Expression.Condition(expr_16, expr_18, expr_15, typeof(string));
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, string>>(expr_19, p_c);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_CustomerTier.IsLoyalty_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_CustomerTier
{
// [Expressive]
// public static bool IsLoyalty(this Customer c) => c.OrderCount() >= 10;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, bool>> IsLoyalty_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_1 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerTier).GetMethod("OrderCount", 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.Customer) }, null), new global::System.Linq.Expressions.Expression[] { p_c }); // c.OrderCount()
var expr_2 = global::System.Linq.Expressions.Expression.Constant(10, typeof(int)); // 10
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_1, expr_2);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, bool>>(expr_0, p_c);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_CustomerTier.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_CustomerTier { }
}
// === 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.CustomerTier).GetMethod("OrderCount", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_CustomerTier", "OrderCount_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Customer_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerTier).GetMethod("Tier", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_CustomerTier", "Tier_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Customer_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerTier).GetMethod("IsLoyalty", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_CustomerTier", "IsLoyalty_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, "RqseBvWZXLxca6n1vX5ToqMBAABfX1NuaXBwZXQuY3M=")]
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: g => new { Tier = g.Key, Count = g.Count() }
var i3e6116c5_p_g = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "g");
var i3e6116c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_g, typeof(T0).GetProperty("Key", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // g.Key
var i3e6116c5_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.Customer)), new global::System.Linq.Expressions.Expression[] { i3e6116c5_p_g }); // g.Count()
var i3e6116c5_expr_3 = typeof(T1).GetConstructors()[0];
var i3e6116c5_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6116c5_expr_3, new global::System.Linq.Expressions.Expression[] { i3e6116c5_expr_1, i3e6116c5_expr_2 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Tier"), typeof(T1).GetProperty("Count") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6116c5_expr_0, i3e6116c5_p_g);
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, "RqseBvWZXLxca6n1vX5ToocBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::System.Linq.IGrouping<string, global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer>> __Polyfill_GroupBy_3e61_15_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, string> __func)
{
// Source: c => c.Tier()
var i3e6115c5_p_c = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer), "c");
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerTier).GetMethod("Tier", 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.Customer) }, null), new global::System.Linq.Expressions.Expression[] { i3e6115c5_p_c }); // c.Tier()
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, string>>(i3e6115c5_expr_0, i3e6115c5_p_c);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.GroupBy(
(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
.GroupBy(c => c.Tier())
.Select(g => new { Tier = g.Key, Count = g.Count() })
// Setup
public static class CustomerTier
{
[Expressive]
public static int OrderCount(this Customer c) => c.Orders.Count();
[Expressive]
public static string Tier(this Customer c) => c.OrderCount() switch
{
>= 50 => "Platinum",
>= 20 and < 50 => "Gold",
>= 5 and < 20 => "Silver",
_ => "Bronze"
};
[Expressive]
public static bool IsLoyalty(this Customer c) => c.OrderCount() >= 10;
}Generated SQL:
SELECT "c0"."Key" AS "Tier", COUNT(*) AS "Count"
FROM (
SELECT CASE
WHEN (
SELECT COUNT(*)
FROM "Orders" AS "o"
WHERE "c"."Id" = "o"."CustomerId") >= 50 THEN 'Platinum'
WHEN (
SELECT COUNT(*)
FROM "Orders" AS "o0"
WHERE "c"."Id" = "o0"."CustomerId") >= 20 AND (
SELECT COUNT(*)
FROM "Orders" AS "o1"
WHERE "c"."Id" = "o1"."CustomerId") < 50 THEN 'Gold'
WHEN (
SELECT COUNT(*)
FROM "Orders" AS "o2"
WHERE "c"."Id" = "o2"."CustomerId") >= 5 AND (
SELECT COUNT(*)
FROM "Orders" AS "o3"
WHERE "c"."Id" = "o3"."CustomerId") < 20 THEN 'Silver'
ELSE 'Bronze'
END AS "Key"
FROM "Customers" AS "c"
) AS "c0"
GROUP BY "c0"."Key"Multi-Field Classification with Property Patterns
Property patterns match on multiple fields of the current instance simultaneously. This is useful for multi-dimensional classification:
db
.Products
.Select(p => new { p.Id, p.Name, Category = p.StockCategory() })
// Setup
public static class StockClassifier
{
[Expressive]
public static string StockCategory(this Product p) => p switch
{
{ StockQuantity: 0 } => "OutOfStock",
{ StockQuantity: < 10, ListPrice: >= 500m } => "LowStockPremium",
{ StockQuantity: < 10 } => "LowStock",
{ StockQuantity: >= 100 } => "WellStocked",
_ => "Normal"
};
}SELECT "p"."Id", "p"."Name", CASE
WHEN "p"."StockQuantity" = 0 THEN 'OutOfStock'
WHEN "p"."StockQuantity" < 10 AND ef_compare("p"."ListPrice", '500.0') >= 0 THEN 'LowStockPremium'
WHEN "p"."StockQuantity" < 10 THEN 'LowStock'
WHEN "p"."StockQuantity" >= 100 THEN 'WellStocked'
ELSE 'Normal'
END AS "Category"
FROM "Products" AS "p"SELECT p."Id", p."Name", CASE
WHEN p."StockQuantity" = 0 THEN 'OutOfStock'
WHEN p."StockQuantity" < 10 AND p."ListPrice" >= 500.0 THEN 'LowStockPremium'
WHEN p."StockQuantity" < 10 THEN 'LowStock'
WHEN p."StockQuantity" >= 100 THEN 'WellStocked'
ELSE 'Normal'
END AS "Category"
FROM "Products" AS pSELECT [p].[Id], [p].[Name], CASE
WHEN [p].[StockQuantity] = 0 THEN N'OutOfStock'
WHEN [p].[StockQuantity] < 10 AND [p].[ListPrice] >= 500.0 THEN N'LowStockPremium'
WHEN [p].[StockQuantity] < 10 THEN N'LowStock'
WHEN [p].[StockQuantity] >= 100 THEN N'WellStocked'
ELSE N'Normal'
END AS [Category]
FROM [Products] AS [p]playground.products.Aggregate([
{
"$project" : {
"_id" : "$_id",
"Name" : "$Name",
"Category" : {
"$cond" : {
"if" : {
"$and" : [
{
"$ne" : ["$$ROOT", null]
},
{
"$eq" : ["$StockQuantity", 0]
}
]
},
"then" : "OutOfStock",
"else" : {
"$cond" : {
"if" : {
"$and" : [
{
"$ne" : ["$$ROOT", null]
},
{
"$lt" : ["$StockQuantity", 10]
},
{
"$gte" : [
"$ListPrice",
{ "$numberDecimal" : "500" }
]
}
]
},
"then" : "LowStockPremium",
"else" : {
"$cond" : {
"if" : {
"$and" : [
{
"$ne" : ["$$ROOT", null]
},
{
"$lt" : ["$StockQuantity", 10]
}
]
},
"then" : "LowStock",
"else" : {
"$cond" : {
"if" : {
"$and" : [
{
"$ne" : ["$$ROOT", null]
},
{
"$gte" : ["$StockQuantity", 100]
}
]
},
"then" : "WellStocked",
"else" : "Normal"
}
}
}
}
}
}
}
}
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_StockClassifier.StockCategory_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_StockClassifier
{
// [Expressive]
// public static string StockCategory(this Product p) => p switch
// {
// { StockQuantity: 0 } => "OutOfStock",
// { StockQuantity: < 10, ListPrice: >= 500m } => "LowStockPremium",
// { StockQuantity: < 10 } => "LowStock",
// { StockQuantity: >= 100 } => "WellStocked",
// _ => "Normal"
// };
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string>> StockCategory_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.Constant("Normal", typeof(string)); // "Normal"
var expr_2 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product));
var expr_1 = global::System.Linq.Expressions.Expression.NotEqual(p_p, expr_2);
var expr_3 = global::System.Linq.Expressions.Expression.Property(p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("StockQuantity", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_5 = global::System.Linq.Expressions.Expression.Constant(100, typeof(int)); // 100
var expr_4 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_3, expr_5);
var expr_6 = global::System.Linq.Expressions.Expression.AndAlso(expr_1, expr_4);
var expr_7 = global::System.Linq.Expressions.Expression.Constant("WellStocked", typeof(string)); // "WellStocked"
var expr_8 = global::System.Linq.Expressions.Expression.Condition(expr_6, expr_7, expr_0, typeof(string));
var expr_10 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product));
var expr_9 = global::System.Linq.Expressions.Expression.NotEqual(p_p, expr_10);
var expr_11 = global::System.Linq.Expressions.Expression.Property(p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("StockQuantity", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_13 = global::System.Linq.Expressions.Expression.Constant(10, typeof(int)); // 10
var expr_12 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.LessThan, expr_11, expr_13);
var expr_14 = global::System.Linq.Expressions.Expression.AndAlso(expr_9, expr_12);
var expr_15 = global::System.Linq.Expressions.Expression.Constant("LowStock", typeof(string)); // "LowStock"
var expr_16 = global::System.Linq.Expressions.Expression.Condition(expr_14, expr_15, expr_8, typeof(string));
var expr_18 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product));
var expr_17 = global::System.Linq.Expressions.Expression.NotEqual(p_p, expr_18);
var expr_19 = global::System.Linq.Expressions.Expression.Property(p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("StockQuantity", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_21 = global::System.Linq.Expressions.Expression.Constant(10, typeof(int)); // 10
var expr_20 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.LessThan, expr_19, expr_21);
var expr_22 = 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));
var expr_24 = global::System.Linq.Expressions.Expression.Constant(500m, typeof(decimal)); // 500m
var expr_23 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_22, expr_24);
var expr_25 = global::System.Linq.Expressions.Expression.AndAlso(expr_17, expr_20);
var expr_26 = global::System.Linq.Expressions.Expression.AndAlso(expr_25, expr_23);
var expr_27 = global::System.Linq.Expressions.Expression.Constant("LowStockPremium", typeof(string)); // "LowStockPremium"
var expr_28 = global::System.Linq.Expressions.Expression.Condition(expr_26, expr_27, expr_16, typeof(string));
var expr_30 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product));
var expr_29 = global::System.Linq.Expressions.Expression.NotEqual(p_p, expr_30);
var expr_31 = global::System.Linq.Expressions.Expression.Property(p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("StockQuantity", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_33 = global::System.Linq.Expressions.Expression.Constant(0, typeof(int)); // 0
var expr_32 = global::System.Linq.Expressions.Expression.Equal(expr_31, expr_33);
var expr_34 = global::System.Linq.Expressions.Expression.AndAlso(expr_29, expr_32);
var expr_35 = global::System.Linq.Expressions.Expression.Constant("OutOfStock", typeof(string)); // "OutOfStock"
var expr_36 = global::System.Linq.Expressions.Expression.Condition(expr_34, expr_35, expr_28, typeof(string));
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string>>(expr_36, p_p);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_StockClassifier.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_StockClassifier { }
}
// === 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.StockClassifier).GetMethod("StockCategory", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_StockClassifier", "StockCategory_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, "pyJmp4drU1WoVUu8RJcQqoYBAABfX1NuaXBwZXQuY3M=")]
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: p => new { p.Id, p.Name, Category = p.StockCategory() }
var i3e6115c5_p_p = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "p");
var i3e6115c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_p_p, typeof(T0).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.Id
var i3e6115c5_expr_2 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_p_p, typeof(T0).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.Name
var i3e6115c5_expr_3 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.StockClassifier).GetMethod("StockCategory", 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[] { i3e6115c5_p_p }); // p.StockCategory()
var i3e6115c5_expr_4 = typeof(T1).GetConstructors()[0];
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6115c5_expr_4, new global::System.Linq.Expressions.Expression[] { i3e6115c5_expr_1, i3e6115c5_expr_2, i3e6115c5_expr_3 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Id"), typeof(T1).GetProperty("Name"), typeof(T1).GetProperty("Category") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6115c5_expr_0, i3e6115c5_p_p);
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
.Products
.Select(p => new { p.Id, p.Name, Category = p.StockCategory() })
// Setup
public static class StockClassifier
{
[Expressive]
public static string StockCategory(this Product p) => p switch
{
{ StockQuantity: 0 } => "OutOfStock",
{ StockQuantity: < 10, ListPrice: >= 500m } => "LowStockPremium",
{ StockQuantity: < 10 } => "LowStock",
{ StockQuantity: >= 100 } => "WellStocked",
_ => "Normal"
};
}Generated SQL:
SELECT "p"."Id", "p"."Name", CASE
WHEN "p"."StockQuantity" = 0 THEN 'OutOfStock'
WHEN "p"."StockQuantity" < 10 AND ef_compare("p"."ListPrice", '500.0') >= 0 THEN 'LowStockPremium'
WHEN "p"."StockQuantity" < 10 THEN 'LowStock'
WHEN "p"."StockQuantity" >= 100 THEN 'WellStocked'
ELSE 'Normal'
END AS "Category"
FROM "Products" AS "p"is Patterns for Boolean Flags
Use is patterns for concise Boolean members:
db
.Products
.Where(p => p.IsInStock() && p.IsBudget())
.Select(p => new { p.Id, p.Name, p.ListPrice })
// Setup
public static class ProductFlags
{
[Expressive]
public static bool IsInStock(this Product p) => p.StockQuantity is > 0;
[Expressive]
public static bool NeedsReorder(this Product p) => p.StockQuantity is >= 0 and <= 5;
[Expressive]
public static bool IsBudget(this Product p) => p.ListPrice is > 0m and < 50m;
[Expressive]
public static bool HasNoStock(this Product p) => p.StockQuantity is 0;
}SELECT "p"."Id", "p"."Name", "p"."ListPrice"
FROM "Products" AS "p"
WHERE "p"."StockQuantity" > 0 AND ef_compare("p"."ListPrice", '0.0') > 0 AND ef_compare("p"."ListPrice", '50.0') < 0SELECT p."Id", p."Name", p."ListPrice"
FROM "Products" AS p
WHERE p."StockQuantity" > 0 AND p."ListPrice" > 0.0 AND p."ListPrice" < 50.0SELECT [p].[Id], [p].[Name], [p].[ListPrice]
FROM [Products] AS [p]
WHERE [p].[StockQuantity] > 0 AND [p].[ListPrice] > 0.0 AND [p].[ListPrice] < 50.0playground.products.Aggregate([
{
"$match" : {
"StockQuantity" : { "$gt" : 0 },
"ListPrice" : {
"$gt" : { "$numberDecimal" : "0" },
"$lt" : { "$numberDecimal" : "50" }
}
}
},
{
"$project" : { "_id" : "$_id", "Name" : "$Name", "ListPrice" : "$ListPrice" }
}
])// === ExpressiveSharp_Docs_Playground_Snippet_ProductFlags.IsInStock_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_ProductFlags
{
// [Expressive]
// public static bool IsInStock(this Product p) => p.StockQuantity is> 0;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool>> IsInStock_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.Property(p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("StockQuantity", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.StockQuantity
var expr_2 = global::System.Linq.Expressions.Expression.Constant(0, typeof(int)); // 0
var expr_1 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThan, expr_0, expr_2);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool>>(expr_1, p_p);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_ProductFlags.NeedsReorder_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_ProductFlags
{
// [Expressive]
// public static bool NeedsReorder(this Product p) => p.StockQuantity is >= 0 and <= 5;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool>> NeedsReorder_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.Property(p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("StockQuantity", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.StockQuantity
var expr_3 = global::System.Linq.Expressions.Expression.Constant(0, typeof(int)); // 0
var expr_2 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_3);
var expr_5 = global::System.Linq.Expressions.Expression.Constant(5, typeof(int)); // 5
var expr_4 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.LessThanOrEqual, expr_0, expr_5);
var expr_1 = global::System.Linq.Expressions.Expression.AndAlso(expr_2, expr_4);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool>>(expr_1, p_p);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_ProductFlags.IsBudget_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_ProductFlags
{
// [Expressive]
// public static bool IsBudget(this Product p) => p.ListPrice is> 0m and < 50m;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool>> IsBudget_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.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_3 = global::System.Linq.Expressions.Expression.Constant(0m, typeof(decimal)); // 0m
var expr_2 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThan, expr_0, expr_3);
var expr_5 = global::System.Linq.Expressions.Expression.Constant(50m, typeof(decimal)); // 50m
var expr_4 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.LessThan, expr_0, expr_5);
var expr_1 = global::System.Linq.Expressions.Expression.AndAlso(expr_2, expr_4);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool>>(expr_1, p_p);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_ProductFlags.HasNoStock_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_ProductFlags
{
// [Expressive]
// public static bool HasNoStock(this Product p) => p.StockQuantity is 0;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool>> HasNoStock_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.Property(p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("StockQuantity", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.StockQuantity
var expr_2 = global::System.Linq.Expressions.Expression.Constant(0, typeof(int)); // 0
var expr_1 = global::System.Linq.Expressions.Expression.Equal(expr_0, expr_2);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool>>(expr_1, p_p);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_ProductFlags.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_ProductFlags { }
}
// === 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.ProductFlags).GetMethod("IsInStock", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_ProductFlags", "IsInStock_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Product_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductFlags).GetMethod("NeedsReorder", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_ProductFlags", "NeedsReorder_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Product_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductFlags).GetMethod("IsBudget", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_ProductFlags", "IsBudget_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Product_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductFlags).GetMethod("HasNoStock", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_ProductFlags", "HasNoStock_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, "ajj/rJuV9IaDgTh2y3vYSrUBAABfX1NuaXBwZXQuY3M=")]
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: p => new { p.Id, p.Name, p.ListPrice }
var i3e6116c5_p_p = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "p");
var i3e6116c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_p, typeof(T0).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.Id
var i3e6116c5_expr_2 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_p, typeof(T0).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.Name
var i3e6116c5_expr_3 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_p, typeof(T0).GetProperty("ListPrice", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.ListPrice
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("Name"), typeof(T1).GetProperty("ListPrice") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6116c5_expr_0, i3e6116c5_p_p);
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, "ajj/rJuV9IaDgTh2y3vYSoYBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product> __Polyfill_Where_3e61_15_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool> __func)
{
// Source: p => p.IsInStock() && p.IsBudget()
var i3e6115c5_p_p = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product), "p");
var i3e6115c5_expr_1 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductFlags).GetMethod("IsInStock", 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.Product) }, null), new global::System.Linq.Expressions.Expression[] { i3e6115c5_p_p }); // p.IsInStock()
var i3e6115c5_expr_2 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductFlags).GetMethod("IsBudget", 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.Product) }, null), new global::System.Linq.Expressions.Expression[] { i3e6115c5_p_p }); // p.IsBudget()
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.Product, bool>>(i3e6115c5_expr_0, i3e6115c5_p_p);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Where(
(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
.Where(p => p.IsInStock() && p.IsBudget())
.Select(p => new { p.Id, p.Name, p.ListPrice })
// Setup
public static class ProductFlags
{
[Expressive]
public static bool IsInStock(this Product p) => p.StockQuantity is > 0;
[Expressive]
public static bool NeedsReorder(this Product p) => p.StockQuantity is >= 0 and <= 5;
[Expressive]
public static bool IsBudget(this Product p) => p.ListPrice is > 0m and < 50m;
[Expressive]
public static bool HasNoStock(this Product p) => p.StockQuantity is 0;
}Generated SQL:
SELECT "p"."Id", "p"."Name", "p"."ListPrice"
FROM "Products" AS "p"
WHERE "p"."StockQuantity" > 0 AND ef_compare("p"."ListPrice", '0.0') > 0 AND ef_compare("p"."ListPrice", '50.0') < 0Positional Patterns
ExpressiveSharp supports positional (deconstruct) patterns. If your type defines a Deconstruct method, you can match on it:
public class Coordinate
{
public double Latitude { get; set; }
public double Longitude { get; set; }
public void Deconstruct(out double lat, out double lon)
{
lat = Latitude;
lon = Longitude;
}
}
public class Location
{
public int Id { get; set; }
public Coordinate Position { get; set; }
[Expressive]
public string Hemisphere => Position switch
{
(>= 0, _) => "Northern",
_ => "Southern"
};
}List Patterns
ExpressiveSharp supports list patterns for fixed-length matching:
public class Measurement
{
public int Id { get; set; }
public int[] Readings { get; set; }
[Expressive]
public string ReadingCategory => Readings switch
{
[0, 0, 0] => "Zero",
[_, _, _] => "Triple",
[_, _] => "Double",
[_] => "Single",
_ => "Other"
};
}Combining Classification with Aggregation
Compose [Expressive] classification members to build rich query results:
db
.Orders
.Where(o => o.IsRecent())
.GroupBy(o => o.ValueBand())
.Select(g => new { Band = g.Key, Count = g.Count(), Total = g.Sum(o => o.GrandTotal()) })
.OrderBy(x => x.Band)
// Setup
public static class OrderScoring
{
[Expressive]
public static decimal GrandTotal(this Order o)
=> o.Items.Sum(i => i.UnitPrice * i.Quantity);
[Expressive]
public static string ValueBand(this Order o) => o.GrandTotal() switch
{
>= 1000m => "High",
>= 250m => "Medium",
_ => "Low"
};
[Expressive]
public static bool IsRecent(this Order o) => o.PlacedAt >= new DateTime(2024, 1, 1);
}SELECT "o0"."Key" AS "Band", COUNT(*) AS "Count", COALESCE(ef_sum((
SELECT COALESCE(ef_sum(ef_multiply("l1"."UnitPrice", CAST("l1"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l1"
WHERE "o0"."Id" = "l1"."OrderId")), '0.0') AS "Total"
FROM (
SELECT "o"."Id", CASE
WHEN ef_compare((
SELECT COALESCE(ef_sum(ef_multiply("l"."UnitPrice", CAST("l"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId"), '1000.0') >= 0 THEN 'High'
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"), '250.0') >= 0 THEN 'Medium'
ELSE 'Low'
END AS "Key"
FROM "Orders" AS "o"
WHERE "o"."PlacedAt" >= '2024-01-01 00:00:00'
) AS "o0"
GROUP BY "o0"."Key"
ORDER BY "o0"."Key"SELECT o0."Key" AS "Band", count(*)::int AS "Count", COALESCE(sum((
SELECT COALESCE(sum(l1."UnitPrice" * l1."Quantity"::numeric(18,2)), 0.0)
FROM "LineItems" AS l1
WHERE o0."Id" = l1."OrderId")), 0.0) AS "Total"
FROM (
SELECT o."Id", CASE
WHEN (
SELECT COALESCE(sum(l."UnitPrice" * l."Quantity"::numeric(18,2)), 0.0)
FROM "LineItems" AS l
WHERE o."Id" = l."OrderId") >= 1000.0 THEN 'High'
WHEN (
SELECT COALESCE(sum(l0."UnitPrice" * l0."Quantity"::numeric(18,2)), 0.0)
FROM "LineItems" AS l0
WHERE o."Id" = l0."OrderId") >= 250.0 THEN 'Medium'
ELSE 'Low'
END AS "Key"
FROM "Orders" AS o
WHERE o."PlacedAt" >= TIMESTAMP '2024-01-01T00:00:00'
) AS o0
GROUP BY o0."Key"
ORDER BY o0."Key"SELECT [o0].[Key] AS [Band], COUNT(*) AS [Count], COALESCE(SUM([s].[value]), 0.0) AS [Total]
FROM (
SELECT [o].[Id], CASE
WHEN (
SELECT COALESCE(SUM([l].[UnitPrice] * CAST([l].[Quantity] AS decimal(18,2))), 0.0)
FROM [LineItems] AS [l]
WHERE [o].[Id] = [l].[OrderId]) >= 1000.0 THEN N'High'
WHEN (
SELECT COALESCE(SUM([l0].[UnitPrice] * CAST([l0].[Quantity] AS decimal(18,2))), 0.0)
FROM [LineItems] AS [l0]
WHERE [o].[Id] = [l0].[OrderId]) >= 250.0 THEN N'Medium'
ELSE N'Low'
END AS [Key]
FROM [Orders] AS [o]
WHERE [o].[PlacedAt] >= '2024-01-01T00:00:00.0000000'
) AS [o0]
OUTER APPLY (
SELECT COALESCE(SUM([l1].[UnitPrice] * CAST([l1].[Quantity] AS decimal(18,2))), 0.0) AS [value]
FROM [LineItems] AS [l1]
WHERE [o0].[Id] = [l1].[OrderId]
) AS [s]
GROUP BY [o0].[Key]
ORDER BY [o0].[Key]playground.orders.Aggregate([
{
"$match" : {
"PlacedAt" : {
"$gte" : { "$date" : "2024-01-01T00:00:00Z" }
}
}
},
{
"$group" : {
"_id" : {
"$cond" : {
"if" : {
"$gte" : [
{
"$sum" : {
"$map" : {
"input" : "$Items",
"as" : "i",
"in" : {
"$multiply" : ["$$i.UnitPrice", "$$i.Quantity"]
}
}
}
},
{ "$numberDecimal" : "1000" }
]
},
"then" : "High",
"else" : {
"$cond" : {
"if" : {
"$gte" : [
{
"$sum" : {
"$map" : {
"input" : "$Items",
"as" : "i",
"in" : {
"$multiply" : ["$$i.UnitPrice", "$$i.Quantity"]
}
}
}
},
{ "$numberDecimal" : "250" }
]
},
"then" : "Medium",
"else" : "Low"
}
}
}
},
"__agg0" : { "$sum" : 1 },
"__agg1" : {
"$sum" : {
"$sum" : {
"$map" : {
"input" : "$Items",
"as" : "i",
"in" : {
"$multiply" : ["$$i.UnitPrice", "$$i.Quantity"]
}
}
}
}
}
}
},
{
"$project" : { "Band" : "$_id", "Count" : "$__agg0", "Total" : "$__agg1", "_id" : 0 }
},
{
"$sort" : { "Band" : 1 }
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderScoring.GrandTotal_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_OrderScoring
{
// [Expressive]
// public static decimal GrandTotal(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>> GrandTotal_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_OrderScoring.ValueBand_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_OrderScoring
{
// [Expressive]
// public static string ValueBand(this Order o) => o.GrandTotal() switch
// {
// >= 1000m => "High",
// >= 250m => "Medium",
// _ => "Low"
// };
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string>> ValueBand_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.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderScoring).GetMethod("GrandTotal", 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[] { p_o }); // o.GrandTotal()
var expr_1 = global::System.Linq.Expressions.Expression.Constant("Low", typeof(string)); // "Low"
var expr_3 = global::System.Linq.Expressions.Expression.Constant(250m, typeof(decimal)); // 250m
var expr_2 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_3);
var expr_4 = global::System.Linq.Expressions.Expression.Constant("Medium", typeof(string)); // "Medium"
var expr_5 = global::System.Linq.Expressions.Expression.Condition(expr_2, expr_4, expr_1, typeof(string));
var expr_7 = global::System.Linq.Expressions.Expression.Constant(1000m, typeof(decimal)); // 1000m
var expr_6 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_7);
var expr_8 = global::System.Linq.Expressions.Expression.Constant("High", typeof(string)); // "High"
var expr_9 = global::System.Linq.Expressions.Expression.Condition(expr_6, expr_8, expr_5, typeof(string));
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string>>(expr_9, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderScoring.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_OrderScoring
{
// [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_OrderScoring.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderScoring { }
}
// === 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.OrderScoring).GetMethod("GrandTotal", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderScoring", "GrandTotal_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderScoring).GetMethod("ValueBand", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderScoring", "ValueBand_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderScoring).GetMethod("IsRecent", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderScoring", "IsRecent_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, "Qy+RgjACeI15vKqhOzC16CECAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T0> __Polyfill_OrderBy_3e61_18_5<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: x => x.Band
var i3e6118c5_p_x = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "x");
var i3e6118c5_expr_0 = global::System.Linq.Expressions.Expression.Property(i3e6118c5_p_x, typeof(T0).GetProperty("Band", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // x.Band
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6118c5_expr_0, i3e6118c5_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, "Qy+RgjACeI15vKqhOzC16MMBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T1> __Polyfill_Select_3e61_17_5<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: g => new { Band = g.Key, Count = g.Count(), Total = g.Sum(o => o.GrandTotal()) }
var i3e6117c5_p_g = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "g");
var i3e6117c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6117c5_p_g, typeof(T0).GetProperty("Key", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // g.Key
var i3e6117c5_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.Order)), new global::System.Linq.Expressions.Expression[] { i3e6117c5_p_g }); // g.Count()
var p_o_4 = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o"); // o => o.GrandTotal()
var i3e6117c5_expr_5 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderScoring).GetMethod("GrandTotal", 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[] { p_o_4 }); // o.GrandTotal()
var i3e6117c5_expr_6 = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, decimal>>(i3e6117c5_expr_5, p_o_4);
var i3e6117c5_expr_3 = 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.Order)), new global::System.Linq.Expressions.Expression[] { i3e6117c5_p_g, i3e6117c5_expr_6 });
var i3e6117c5_expr_7 = typeof(T1).GetConstructors()[0];
var i3e6117c5_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6117c5_expr_7, new global::System.Linq.Expressions.Expression[] { i3e6117c5_expr_1, i3e6117c5_expr_2, i3e6117c5_expr_3 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Band"), typeof(T1).GetProperty("Count"), typeof(T1).GetProperty("Total") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6117c5_expr_0, i3e6117c5_p_g);
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, "Qy+RgjACeI15vKqhOzC16KIBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::System.Linq.IGrouping<string, global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>> __Polyfill_GroupBy_3e61_16_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.ValueBand()
var i3e6116c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6116c5_expr_0 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderScoring).GetMethod("ValueBand", 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[] { i3e6116c5_p_o }); // o.ValueBand()
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string>>(i3e6116c5_expr_0, i3e6116c5_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.GroupBy(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "Qy+RgjACeI15vKqhOzC16IQBAABfX1NuaXBwZXQuY3M=")]
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()
var i3e6115c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderScoring).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 __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())
.GroupBy(o => o.ValueBand())
.Select(g => new { Band = g.Key, Count = g.Count(), Total = g.Sum(o => o.GrandTotal()) })
.OrderBy(x => x.Band)
// Setup
public static class OrderScoring
{
[Expressive]
public static decimal GrandTotal(this Order o)
=> o.Items.Sum(i => i.UnitPrice * i.Quantity);
[Expressive]
public static string ValueBand(this Order o) => o.GrandTotal() switch
{
>= 1000m => "High",
>= 250m => "Medium",
_ => "Low"
};
[Expressive]
public static bool IsRecent(this Order o) => o.PlacedAt >= new DateTime(2024, 1, 1);
}Generated SQL:
SELECT "o0"."Key" AS "Band", COUNT(*) AS "Count", COALESCE(ef_sum((
SELECT COALESCE(ef_sum(ef_multiply("l1"."UnitPrice", CAST("l1"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l1"
WHERE "o0"."Id" = "l1"."OrderId")), '0.0') AS "Total"
FROM (
SELECT "o"."Id", CASE
WHEN ef_compare((
SELECT COALESCE(ef_sum(ef_multiply("l"."UnitPrice", CAST("l"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId"), '1000.0') >= 0 THEN 'High'
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"), '250.0') >= 0 THEN 'Medium'
ELSE 'Low'
END AS "Key"
FROM "Orders" AS "o"
WHERE "o"."PlacedAt" >= '2024-01-01 00:00:00'
) AS "o0"
GROUP BY "o0"."Key"
ORDER BY "o0"."Key"Using Switch Expressions Inline in LINQ Chains
You can also use switch expressions directly in LINQ chains via ExpressiveDbSet<T> or IExpressiveQueryable<T>, without defining a separate [Expressive] member:
db
.Orders
.Select(o => new
{
o.Id,
Tier = o.Status switch
{
OrderStatus.Delivered => "Completed",
OrderStatus.Shipped => "InTransit",
OrderStatus.Paid => "Awaiting",
OrderStatus.Pending => "New",
_ => "Other"
}
}).param set @Delivered 3
.param set @Shipped 2
.param set @Paid 1
.param set @Pending 0
SELECT "o"."Id", CASE
WHEN "o"."Status" = @Delivered THEN 'Completed'
WHEN "o"."Status" = @Shipped THEN 'InTransit'
WHEN "o"."Status" = @Paid THEN 'Awaiting'
WHEN "o"."Status" = @Pending THEN 'New'
ELSE 'Other'
END AS "Tier"
FROM "Orders" AS "o"-- @Delivered='3'
-- @Shipped='2'
-- @Paid='1'
-- @Pending='0'
SELECT o."Id", CASE
WHEN o."Status" = @Delivered THEN 'Completed'
WHEN o."Status" = @Shipped THEN 'InTransit'
WHEN o."Status" = @Paid THEN 'Awaiting'
WHEN o."Status" = @Pending THEN 'New'
ELSE 'Other'
END AS "Tier"
FROM "Orders" AS oDECLARE @Delivered int = 3;
DECLARE @Shipped int = 2;
DECLARE @Paid int = 1;
DECLARE @Pending int = 0;
SELECT [o].[Id], CASE
WHEN [o].[Status] = @Delivered THEN N'Completed'
WHEN [o].[Status] = @Shipped THEN N'InTransit'
WHEN [o].[Status] = @Paid THEN N'Awaiting'
WHEN [o].[Status] = @Pending THEN N'New'
ELSE N'Other'
END AS [Tier]
FROM [Orders] AS [o]playground.orders.Aggregate([
{
"$project" : {
"_id" : "$_id",
"Tier" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 3]
},
"then" : "Completed",
"else" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 2]
},
"then" : "InTransit",
"else" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 1]
},
"then" : "Awaiting",
"else" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 0]
},
"then" : "New",
"else" : "Other"
}
}
}
}
}
}
}
}
}
}
])// === PolyfillInterceptors_b1293e61.g.cs ===
// <auto-generated/>
#nullable disable
namespace ExpressiveSharp.Generated.Interceptors
{
internal static partial class PolyfillInterceptors
{
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "3sqdhpnx0cMycJB8vdvGFYQBAABfX1NuaXBwZXQuY3M=")]
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.Status switch { OrderStatus.Delivered => "Completed", OrderStatus.Shipped => "InTransit", OrderStatus.Paid => "Awaiting", OrderStatus.Pending => "New", _ => "Other" } }
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_2 = 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_3 = global::System.Linq.Expressions.Expression.Constant("Other", typeof(string)); // "Other"
var i3e6115c5_expr_5 = 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_4 = global::System.Linq.Expressions.Expression.Equal(i3e6115c5_expr_2, i3e6115c5_expr_5);
var i3e6115c5_expr_6 = global::System.Linq.Expressions.Expression.Constant("New", typeof(string)); // "New"
var i3e6115c5_expr_7 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_4, i3e6115c5_expr_6, i3e6115c5_expr_3, typeof(string));
var i3e6115c5_expr_9 = 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_8 = global::System.Linq.Expressions.Expression.Equal(i3e6115c5_expr_2, i3e6115c5_expr_9);
var i3e6115c5_expr_10 = global::System.Linq.Expressions.Expression.Constant("Awaiting", typeof(string)); // "Awaiting"
var i3e6115c5_expr_11 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_8, i3e6115c5_expr_10, i3e6115c5_expr_7, typeof(string));
var i3e6115c5_expr_13 = global::System.Linq.Expressions.Expression.Field(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus).GetField("Shipped", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static)); // OrderStatus.Shipped
var i3e6115c5_expr_12 = global::System.Linq.Expressions.Expression.Equal(i3e6115c5_expr_2, i3e6115c5_expr_13);
var i3e6115c5_expr_14 = global::System.Linq.Expressions.Expression.Constant("InTransit", typeof(string)); // "InTransit"
var i3e6115c5_expr_15 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_12, i3e6115c5_expr_14, i3e6115c5_expr_11, typeof(string));
var i3e6115c5_expr_17 = global::System.Linq.Expressions.Expression.Field(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus).GetField("Delivered", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static)); // OrderStatus.Delivered
var i3e6115c5_expr_16 = global::System.Linq.Expressions.Expression.Equal(i3e6115c5_expr_2, i3e6115c5_expr_17);
var i3e6115c5_expr_18 = global::System.Linq.Expressions.Expression.Constant("Completed", typeof(string)); // "Completed"
var i3e6115c5_expr_19 = global::System.Linq.Expressions.Expression.Condition(i3e6115c5_expr_16, i3e6115c5_expr_18, i3e6115c5_expr_15, typeof(string));
var i3e6115c5_expr_20 = typeof(T1).GetConstructors()[0];
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6115c5_expr_20, new global::System.Linq.Expressions.Expression[] { i3e6115c5_expr_1, i3e6115c5_expr_19 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Id"), typeof(T1).GetProperty("Tier") });
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.Status switch
{
OrderStatus.Delivered => "Completed",
OrderStatus.Shipped => "InTransit",
OrderStatus.Paid => "Awaiting",
OrderStatus.Pending => "New",
_ => "Other"
}
})Generated SQL:
.param set @Delivered 3
.param set @Shipped 2
.param set @Paid 1
.param set @Pending 0
SELECT "o"."Id", CASE
WHEN "o"."Status" = @Delivered THEN 'Completed'
WHEN "o"."Status" = @Shipped THEN 'InTransit'
WHEN "o"."Status" = @Paid THEN 'Awaiting'
WHEN "o"."Status" = @Pending THEN 'New'
ELSE 'Other'
END AS "Tier"
FROM "Orders" AS "o"See Modern Syntax in LINQ Chains for more on this approach.
Tips
Use _ as the default arm
Always include a discard arm to avoid generating a ternary chain with no final fallback. This prevents potential null results.
Keep arms ordered from most to least specific
The generator emits a ternary chain in arm order. Put the most restrictive cases first for correct evaluation.
Compose with filters
Classification members work in Where, GroupBy, and OrderBy just like any other [Expressive] member. This is how you build reporting queries that compute business categories entirely in SQL.
See Also
- Computed Entity Properties -- building blocks for classification
- Modern Syntax in LINQ Chains -- switch expressions inline in queries
- Nullable Navigation Properties -- safely handling null in classification logic
