Pattern Matching
The ExpressiveSharp source generator rewrites C# pattern-matching constructs into expression-tree-compatible ternary and binary expressions. LINQ providers translate these into their native conditional syntax (SQL CASE, MongoDB $cond/$switch, etc.).
Supported Patterns
| Pattern | Context | Example |
|---|---|---|
| Constant | switch arm, is | 1 => "one", Value is 42 |
| Discard / default | switch arm | _ => "other" |
| Type | switch arm | GroupItem g => ... |
| Relational | switch arm, is | >= 90 => "A", Value is > 0 |
and combined | switch arm, is | >= 80 and < 90, Value is >= 1 and <= 100 |
or combined | switch arm, is | 1 or 2 => "low", Value is 0 or > 100 |
not | is | Name is not null |
when guard | switch arm | 4 when IsSpecial => ... |
| Property | switch arm, is | entity is { IsActive: true } |
| Positional / deconstruct | switch arm, is | (0, 0) => "origin" |
| List (fixed-length) | is | [1, 2, 3] |
| List (slice) | is | [1, .., 3] |
var | switch arm | var x when x > 0 => ... |
is Patterns in Expression Bodies
Relational and / or
A range check using an [Expressive] helper. The tabs show how each provider translates it.
db
.Products
.Where(p => p.IsReasonablyPriced())
.Select(p => p.Name)
// Setup
public static class ProductExt
{
[Expressive]
public static bool IsReasonablyPriced(this Product p) => p.ListPrice is >= 1m and <= 100m;
}SELECT "p"."Name"
FROM "Products" AS "p"
WHERE ef_compare("p"."ListPrice", '1.0') >= 0 AND ef_compare("p"."ListPrice", '100.0') <= 0SELECT p."Name"
FROM "Products" AS p
WHERE p."ListPrice" >= 1.0 AND p."ListPrice" <= 100.0SELECT [p].[Name]
FROM [Products] AS [p]
WHERE [p].[ListPrice] >= 1.0 AND [p].[ListPrice] <= 100.0playground.products.Aggregate([
{
"$match" : {
"ListPrice" : {
"$gte" : { "$numberDecimal" : "1" },
"$lte" : { "$numberDecimal" : "100" }
}
}
},
{
"$project" : { "_v" : "$Name", "_id" : 0 }
}
])// === ExpressiveSharp_Docs_Playground_Snippet_ProductExt.IsReasonablyPriced_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_ProductExt
{
// [Expressive]
// public static bool IsReasonablyPriced(this Product p) => p.ListPrice is >= 1m and <= 100m;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool>> IsReasonablyPriced_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(1m, typeof(decimal)); // 1m
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(100m, typeof(decimal)); // 100m
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_ProductExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_ProductExt { }
}
// === 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.ProductExt).GetMethod("IsReasonablyPriced", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_ProductExt", "IsReasonablyPriced_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, "60ChfcIqfP54N00e5AFNbaQBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<string> __Polyfill_Select_3e61_14_58(
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.Name
var i3e6114c58_p_p = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product), "p");
var i3e6114c58_expr_0 = global::System.Linq.Expressions.Expression.Property(i3e6114c58_p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.Name
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string>>(i3e6114c58_expr_0, i3e6114c58_p_p);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product>)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "60ChfcIqfP54N00e5AFNbYEBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product> __Polyfill_Where_3e61_14_23(
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.IsReasonablyPriced()
var i3e6114c23_p_p = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product), "p");
var i3e6114c23_expr_0 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductExt).GetMethod("IsReasonablyPriced", 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[] { i3e6114c23_p_p }); // p.IsReasonablyPriced()
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, bool>>(i3e6114c23_expr_0, i3e6114c23_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.IsReasonablyPriced())
.Select(p => p.Name)
// Setup
public static class ProductExt
{
[Expressive]
public static bool IsReasonablyPriced(this Product p) => p.ListPrice is >= 1m and <= 100m;
}Generated SQL:
SELECT "p"."Name"
FROM "Products" AS "p"
WHERE ef_compare("p"."ListPrice", '1.0') >= 0 AND ef_compare("p"."ListPrice", '100.0') <= 0Alternative values with or:
db
.Orders
.Where(o => o.IsBoundary())
.Select(o => o.Id)
// Setup
public static class OrderExt
{
[Expressive]
public static bool IsBoundary(this Order o) => o.Items.Count is 0 or 100;
}SELECT "o"."Id"
FROM "Orders" AS "o"
WHERE (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") = 0 OR (
SELECT COUNT(*)
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId") = 100SELECT o."Id"
FROM "Orders" AS o
WHERE (
SELECT count(*)::int
FROM "LineItems" AS l
WHERE o."Id" = l."OrderId") = 0 OR (
SELECT count(*)::int
FROM "LineItems" AS l0
WHERE o."Id" = l0."OrderId") = 100SELECT [o].[Id]
FROM [Orders] AS [o]
WHERE (
SELECT COUNT(*)
FROM [LineItems] AS [l]
WHERE [o].[Id] = [l].[OrderId]) = 0 OR (
SELECT COUNT(*)
FROM [LineItems] AS [l0]
WHERE [o].[Id] = [l0].[OrderId]) = 100playground.orders.Aggregate([
{
"$match" : {
"$or" : [
{
"Items" : { "$size" : 0 }
},
{
"Items" : { "$size" : 100 }
}
]
}
},
{
"$project" : { "_v" : "$_id", "_id" : 0 }
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.IsBoundary_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt
{
// [Expressive]
// public static bool IsBoundary(this Order o) => o.Items.Count is 0 or 100;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>> IsBoundary_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression()
{
var p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var expr_1 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Items", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Items
var expr_0 = global::System.Linq.Expressions.Expression.Property(expr_1, typeof(global::System.Collections.Generic.ICollection<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem>).GetProperty("Count", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_4 = global::System.Linq.Expressions.Expression.Constant(0, typeof(int)); // 0
var expr_3 = global::System.Linq.Expressions.Expression.Equal(expr_0, expr_4);
var expr_6 = global::System.Linq.Expressions.Expression.Constant(100, typeof(int)); // 100
var expr_5 = global::System.Linq.Expressions.Expression.Equal(expr_0, expr_6);
var expr_2 = global::System.Linq.Expressions.Expression.OrElse(expr_3, expr_5);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(expr_2, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt { }
}
// === ExpressionRegistry.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static class ExpressionRegistry
{
private static Dictionary<nint, LambdaExpression> Build()
{
const BindingFlags allFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
var map = new Dictionary<nint, LambdaExpression>();
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("IsBoundary", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderExt", "IsBoundary_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, "8CCMZGVM5dg2PK6KIFlnoJoBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<int> __Polyfill_Select_3e61_14_48(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, int> __func)
{
// Source: o => o.Id
var i3e6114c48_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6114c48_expr_0 = global::System.Linq.Expressions.Expression.Property(i3e6114c48_p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, int>>(i3e6114c48_expr_0, i3e6114c48_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "8CCMZGVM5dg2PK6KIFlnoH8BAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_Where_3e61_14_21(
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.IsBoundary()
var i3e6114c21_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6114c21_expr_0 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("IsBoundary", 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[] { i3e6114c21_p_o }); // o.IsBoundary()
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(i3e6114c21_expr_0, i3e6114c21_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.IsBoundary())
.Select(o => o.Id)
// Setup
public static class OrderExt
{
[Expressive]
public static bool IsBoundary(this Order o) => o.Items.Count is 0 or 100;
}Generated SQL:
SELECT "o"."Id"
FROM "Orders" AS "o"
WHERE (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") = 0 OR (
SELECT COUNT(*)
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId") = 100not null / not
db
.Customers
.Where(c => c.HasEmail())
.Select(c => c.Name)
// Setup
public static class CustomerExt
{
[Expressive]
public static bool HasEmail(this Customer c) => c.Email is not null;
}SELECT "c"."Name"
FROM "Customers" AS "c"
WHERE "c"."Email" IS NOT NULLSELECT c."Name"
FROM "Customers" AS c
WHERE c."Email" IS NOT NULLSELECT [c].[Name]
FROM [Customers] AS [c]
WHERE [c].[Email] IS NOT NULLplayground.customers.Aggregate([
{
"$match" : {
"Email" : { "$ne" : null }
}
},
{
"$project" : { "_v" : "$Name", "_id" : 0 }
}
])// === ExpressiveSharp_Docs_Playground_Snippet_CustomerExt.HasEmail_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_CustomerExt
{
// [Expressive]
// public static bool HasEmail(this Customer c) => c.Email is not null;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, bool>> HasEmail_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.Property(p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Email", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Email
var expr_4 = global::System.Linq.Expressions.Expression.Constant(null, typeof(object)); // null
var expr_3 = global::System.Linq.Expressions.Expression.Convert(expr_4, typeof(string));
var expr_2 = global::System.Linq.Expressions.Expression.Equal(expr_0, expr_3);
var expr_1 = global::System.Linq.Expressions.Expression.Not(expr_2);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, bool>>(expr_1, p_c);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_CustomerExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_CustomerExt { }
}
// === 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.CustomerExt).GetMethod("HasEmail", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_CustomerExt", "HasEmail_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, "Zp2F+472mR6pLyNY835zO5sBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<string> __Polyfill_Select_3e61_14_49(
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.Name
var i3e6114c49_p_c = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer), "c");
var i3e6114c49_expr_0 = global::System.Linq.Expressions.Expression.Property(i3e6114c49_p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Name
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, string>>(i3e6114c49_expr_0, i3e6114c49_p_c);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer>)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "Zp2F+472mR6pLyNY835zO4IBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer> __Polyfill_Where_3e61_14_24(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, bool> __func)
{
// Source: c => c.HasEmail()
var i3e6114c24_p_c = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer), "c");
var i3e6114c24_expr_0 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerExt).GetMethod("HasEmail", 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[] { i3e6114c24_p_c }); // c.HasEmail()
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, bool>>(i3e6114c24_expr_0, i3e6114c24_p_c);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Where(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer>)source,
__lambda));
}
}
}
namespace System.Runtime.CompilerServices
{
[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : global::System.Attribute
{
public InterceptsLocationAttribute(int version, string data) { }
}
}db
.Customers
.Where(c => c.HasEmail())
.Select(c => c.Name)
// Setup
public static class CustomerExt
{
[Expressive]
public static bool HasEmail(this Customer c) => c.Email is not null;
}Generated SQL:
SELECT "c"."Name"
FROM "Customers" AS "c"
WHERE "c"."Email" IS NOT NULLProperty Patterns
db
.Orders
.Where(o => o.IsLargePaid())
.Select(o => o.Id)
// Setup
public static class OrderExt
{
[Expressive]
public static bool IsLargePaid(this Order o) =>
o is { Status: ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus.Paid, Items.Count: > 5 };
}.param set @Paid 1
SELECT "o"."Id"
FROM "Orders" AS "o"
WHERE "o"."Status" = @Paid AND (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") > 5-- @Paid='1'
SELECT o."Id"
FROM "Orders" AS o
WHERE o."Status" = @Paid AND (
SELECT count(*)::int
FROM "LineItems" AS l
WHERE o."Id" = l."OrderId") > 5DECLARE @Paid int = 1;
SELECT [o].[Id]
FROM [Orders] AS [o]
WHERE [o].[Status] = @Paid AND (
SELECT COUNT(*)
FROM [LineItems] AS [l]
WHERE [o].[Id] = [l].[OrderId]) > 5playground.orders.Aggregate([
{
"$match" : {
"$and" : [
{
"$expr" : {
"$ne" : ["$$ROOT", null]
}
},
{ "Status" : 1 },
{
"Items" : { "$ne" : null }
},
{
"Items.5" : { "$exists" : true }
}
]
}
},
{
"$project" : { "_v" : "$_id", "_id" : 0 }
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.IsLargePaid_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt
{
// [Expressive]
// public static bool IsLargePaid(this Order o) => o is { Status: ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus.Paid, Items.Count: > 5 };
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>> IsLargePaid_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.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order)); // o is { Status: ExpressiveSharp.Docs.PlaygroundModel.Websh...
var expr_0 = global::System.Linq.Expressions.Expression.NotEqual(p_o, expr_1);
var expr_2 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Status", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_4 = 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)); // ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus....
var expr_3 = global::System.Linq.Expressions.Expression.Equal(expr_2, expr_4);
var expr_5 = 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));
var expr_7 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::System.Collections.Generic.ICollection<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem>));
var expr_6 = global::System.Linq.Expressions.Expression.NotEqual(expr_5, expr_7);
var expr_8 = global::System.Linq.Expressions.Expression.Property(expr_5, typeof(global::System.Collections.Generic.ICollection<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem>).GetProperty("Count", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_10 = global::System.Linq.Expressions.Expression.Constant(5, typeof(int)); // 5
var expr_9 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThan, expr_8, expr_10);
var expr_11 = global::System.Linq.Expressions.Expression.AndAlso(expr_6, expr_9);
var expr_12 = global::System.Linq.Expressions.Expression.AndAlso(expr_0, expr_3);
var expr_13 = global::System.Linq.Expressions.Expression.AndAlso(expr_12, expr_11);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(expr_13, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt { }
}
// === ExpressionRegistry.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static class ExpressionRegistry
{
private static Dictionary<nint, LambdaExpression> Build()
{
const BindingFlags allFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
var map = new Dictionary<nint, LambdaExpression>();
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("IsLargePaid", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderExt", "IsLargePaid_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, "278NWZiW3VEtNWeiNnTlxJsBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<int> __Polyfill_Select_3e61_14_49(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, int> __func)
{
// Source: o => o.Id
var i3e6114c49_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6114c49_expr_0 = global::System.Linq.Expressions.Expression.Property(i3e6114c49_p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, int>>(i3e6114c49_expr_0, i3e6114c49_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "278NWZiW3VEtNWeiNnTlxH8BAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_Where_3e61_14_21(
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.IsLargePaid()
var i3e6114c21_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6114c21_expr_0 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("IsLargePaid", 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[] { i3e6114c21_p_o }); // o.IsLargePaid()
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(i3e6114c21_expr_0, i3e6114c21_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.IsLargePaid())
.Select(o => o.Id)
// Setup
public static class OrderExt
{
[Expressive]
public static bool IsLargePaid(this Order o) =>
o is { Status: ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus.Paid, Items.Count: > 5 };
}Generated SQL:
.param set @Paid 1
SELECT "o"."Id"
FROM "Orders" AS "o"
WHERE "o"."Status" = @Paid AND (
SELECT COUNT(*)
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId") > 5Property patterns can be nested:
db
.Orders
.Where(o => o.HasNamedCustomer())
.Select(o => o.Id)
// Setup
public static class OrderExt
{
[Expressive]
public static bool HasNamedCustomer(this Order o) =>
o is { Customer: { Name: not null, Country: not null } };
}SELECT "o"."Id"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "c"."Country" IS NOT NULLSELECT o."Id"
FROM "Orders" AS o
INNER JOIN "Customers" AS c ON o."CustomerId" = c."Id"
WHERE c."Country" IS NOT NULLSELECT [o].[Id]
FROM [Orders] AS [o]
INNER JOIN [Customers] AS [c] ON [o].[CustomerId] = [c].[Id]
WHERE [c].[Country] IS NOT NULLplayground.orders.Aggregate([
{
"$match" : {
"$and" : [
{
"$expr" : {
"$ne" : ["$$ROOT", null]
}
},
{
"Customer" : { "$ne" : null }
},
{
"Customer.Name" : { "$ne" : null }
},
{
"Customer.Country" : { "$ne" : null }
}
]
}
},
{
"$project" : { "_v" : "$_id", "_id" : 0 }
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.HasNamedCustomer_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt
{
// [Expressive]
// public static bool HasNamedCustomer(this Order o) => o is { Customer: { Name: not null, Country: not null } };
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>> HasNamedCustomer_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.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order)); // o is { Customer: { Name: not null, Country: not null } }
var expr_0 = global::System.Linq.Expressions.Expression.NotEqual(p_o, expr_1);
var expr_2 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_4 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer));
var expr_3 = global::System.Linq.Expressions.Expression.NotEqual(expr_2, expr_4);
var expr_5 = global::System.Linq.Expressions.Expression.Property(expr_2, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_9 = global::System.Linq.Expressions.Expression.Constant(null, typeof(object)); // null
var expr_8 = global::System.Linq.Expressions.Expression.Convert(expr_9, typeof(string));
var expr_7 = global::System.Linq.Expressions.Expression.Equal(expr_5, expr_8);
var expr_6 = global::System.Linq.Expressions.Expression.Not(expr_7);
var expr_10 = global::System.Linq.Expressions.Expression.Property(expr_2, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Country", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_14 = global::System.Linq.Expressions.Expression.Constant(null, typeof(object)); // null
var expr_13 = global::System.Linq.Expressions.Expression.Convert(expr_14, typeof(string));
var expr_12 = global::System.Linq.Expressions.Expression.Equal(expr_10, expr_13);
var expr_11 = global::System.Linq.Expressions.Expression.Not(expr_12);
var expr_15 = global::System.Linq.Expressions.Expression.AndAlso(expr_3, expr_6);
var expr_16 = global::System.Linq.Expressions.Expression.AndAlso(expr_15, expr_11);
var expr_17 = global::System.Linq.Expressions.Expression.AndAlso(expr_0, expr_16);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(expr_17, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt { }
}
// === ExpressionRegistry.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static class ExpressionRegistry
{
private static Dictionary<nint, LambdaExpression> Build()
{
const BindingFlags allFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
var map = new Dictionary<nint, LambdaExpression>();
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("HasNamedCustomer", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderExt", "HasNamedCustomer_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, "IEXczphLG1wKmWqLGDNe9aABAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<int> __Polyfill_Select_3e61_14_54(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, int> __func)
{
// Source: o => o.Id
var i3e6114c54_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6114c54_expr_0 = global::System.Linq.Expressions.Expression.Property(i3e6114c54_p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, int>>(i3e6114c54_expr_0, i3e6114c54_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "IEXczphLG1wKmWqLGDNe9X8BAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_Where_3e61_14_21(
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.HasNamedCustomer()
var i3e6114c21_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6114c21_expr_0 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("HasNamedCustomer", 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[] { i3e6114c21_p_o }); // o.HasNamedCustomer()
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(i3e6114c21_expr_0, i3e6114c21_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.HasNamedCustomer())
.Select(o => o.Id)
// Setup
public static class OrderExt
{
[Expressive]
public static bool HasNamedCustomer(this Order o) =>
o is { Customer: { Name: not null, Country: not null } };
}Generated SQL:
SELECT "o"."Id"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "c"."Country" IS NOT NULLPositional / Deconstruct Patterns
Types that expose a Deconstruct method can use positional patterns:
[Expressive]
public string Classify(Point p) => p switch
{
(0, 0) => "Origin",
(> 0, > 0) => "Quadrant 1",
_ => "Other",
};List Patterns
Fixed-length and slice patterns are supported on array and list types:
[Expressive]
public bool StartsWithOne(int[] arr) => arr is [1, ..];
[Expressive]
public bool IsTriple(int[] arr) => arr is [_, _, _];Switch Expressions with Patterns
Switch expressions are the most common use of pattern matching in [Expressive] members. See Switch Expressions for a dedicated reference.
Relational and Constant Patterns
db
.Products
.Select(p => new { p.Name, Grade = p.GetGrade() })
// Setup
public static class ProductExt
{
[Expressive]
public static string GetGrade(this Product p) => p.ListPrice switch
{
>= 500m => "A",
>= 100m => "B",
>= 20m => "C",
_ => "F",
};
}SELECT "p"."Name", CASE
WHEN ef_compare("p"."ListPrice", '500.0') >= 0 THEN 'A'
WHEN ef_compare("p"."ListPrice", '100.0') >= 0 THEN 'B'
WHEN ef_compare("p"."ListPrice", '20.0') >= 0 THEN 'C'
ELSE 'F'
END AS "Grade"
FROM "Products" AS "p"SELECT p."Name", CASE
WHEN p."ListPrice" >= 500.0 THEN 'A'
WHEN p."ListPrice" >= 100.0 THEN 'B'
WHEN p."ListPrice" >= 20.0 THEN 'C'
ELSE 'F'
END AS "Grade"
FROM "Products" AS pSELECT [p].[Name], CASE
WHEN [p].[ListPrice] >= 500.0 THEN N'A'
WHEN [p].[ListPrice] >= 100.0 THEN N'B'
WHEN [p].[ListPrice] >= 20.0 THEN N'C'
ELSE N'F'
END AS [Grade]
FROM [Products] AS [p]playground.products.Aggregate([
{
"$project" : {
"Name" : "$Name",
"Grade" : {
"$cond" : {
"if" : {
"$gte" : [
"$ListPrice",
{ "$numberDecimal" : "500" }
]
},
"then" : "A",
"else" : {
"$cond" : {
"if" : {
"$gte" : [
"$ListPrice",
{ "$numberDecimal" : "100" }
]
},
"then" : "B",
"else" : {
"$cond" : {
"if" : {
"$gte" : [
"$ListPrice",
{ "$numberDecimal" : "20" }
]
},
"then" : "C",
"else" : "F"
}
}
}
}
}
},
"_id" : 0
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_ProductExt.GetGrade_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_ProductExt
{
// [Expressive]
// public static string GetGrade(this Product p) => p.ListPrice switch
// {
// >= 500m => "A",
// >= 100m => "B",
// >= 20m => "C",
// _ => "F",
// };
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string>> GetGrade_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("F", typeof(string)); // "F"
var expr_3 = global::System.Linq.Expressions.Expression.Constant(20m, typeof(decimal)); // 20m
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("C", typeof(string)); // "C"
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("B", typeof(string)); // "B"
var expr_9 = global::System.Linq.Expressions.Expression.Condition(expr_6, expr_8, expr_5, typeof(string));
var expr_11 = global::System.Linq.Expressions.Expression.Constant(500m, typeof(decimal)); // 500m
var expr_10 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_11);
var expr_12 = global::System.Linq.Expressions.Expression.Constant("A", typeof(string)); // "A"
var expr_13 = global::System.Linq.Expressions.Expression.Condition(expr_10, expr_12, expr_9, typeof(string));
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string>>(expr_13, p_p);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_ProductExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_ProductExt { }
}
// === 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.ProductExt).GetMethod("GetGrade", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_ProductExt", "GetGrade_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, "CIx299xx//nwL9fyx8jWkoEBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T1> __Polyfill_Select_3e61_14_23<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: p => new { p.Name, Grade = p.GetGrade() }
var i3e6114c23_p_p = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "p");
var i3e6114c23_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6114c23_p_p, typeof(T0).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.Name
var i3e6114c23_expr_2 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductExt).GetMethod("GetGrade", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(T0) }, null), new global::System.Linq.Expressions.Expression[] { i3e6114c23_p_p }); // p.GetGrade()
var i3e6114c23_expr_3 = typeof(T1).GetConstructors()[0];
var i3e6114c23_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6114c23_expr_3, new global::System.Linq.Expressions.Expression[] { i3e6114c23_expr_1, i3e6114c23_expr_2 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Name"), typeof(T1).GetProperty("Grade") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6114c23_expr_0, i3e6114c23_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.Name, Grade = p.GetGrade() })
// Setup
public static class ProductExt
{
[Expressive]
public static string GetGrade(this Product p) => p.ListPrice switch
{
>= 500m => "A",
>= 100m => "B",
>= 20m => "C",
_ => "F",
};
}Generated SQL:
SELECT "p"."Name", CASE
WHEN ef_compare("p"."ListPrice", '500.0') >= 0 THEN 'A'
WHEN ef_compare("p"."ListPrice", '100.0') >= 0 THEN 'B'
WHEN ef_compare("p"."ListPrice", '20.0') >= 0 THEN 'C'
ELSE 'F'
END AS "Grade"
FROM "Products" AS "p"The tabs above show how each provider renders the generated ternary chain.
and / or Combined Patterns
db
.Products
.Select(p => new { p.Name, Band = p.GetBand() })
// Setup
public static class ProductExt
{
[Expressive]
public static string GetBand(this Product p) => p.StockQuantity switch
{
>= 90 and <= 100 => "Excellent",
>= 70 and < 90 => "Good",
_ => "Poor",
};
}SELECT "p"."Name", CASE
WHEN "p"."StockQuantity" >= 90 AND "p"."StockQuantity" <= 100 THEN 'Excellent'
WHEN "p"."StockQuantity" >= 70 AND "p"."StockQuantity" < 90 THEN 'Good'
ELSE 'Poor'
END AS "Band"
FROM "Products" AS "p"SELECT p."Name", CASE
WHEN p."StockQuantity" >= 90 AND p."StockQuantity" <= 100 THEN 'Excellent'
WHEN p."StockQuantity" >= 70 AND p."StockQuantity" < 90 THEN 'Good'
ELSE 'Poor'
END AS "Band"
FROM "Products" AS pSELECT [p].[Name], CASE
WHEN [p].[StockQuantity] >= 90 AND [p].[StockQuantity] <= 100 THEN N'Excellent'
WHEN [p].[StockQuantity] >= 70 AND [p].[StockQuantity] < 90 THEN N'Good'
ELSE N'Poor'
END AS [Band]
FROM [Products] AS [p]playground.products.Aggregate([
{
"$project" : {
"Name" : "$Name",
"Band" : {
"$cond" : {
"if" : {
"$and" : [
{
"$gte" : ["$StockQuantity", 90]
},
{
"$lte" : ["$StockQuantity", 100]
}
]
},
"then" : "Excellent",
"else" : {
"$cond" : {
"if" : {
"$and" : [
{
"$gte" : ["$StockQuantity", 70]
},
{
"$lt" : ["$StockQuantity", 90]
}
]
},
"then" : "Good",
"else" : "Poor"
}
}
}
},
"_id" : 0
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_ProductExt.GetBand_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_ProductExt
{
// [Expressive]
// public static string GetBand(this Product p) => p.StockQuantity switch
// {
// >= 90 and <= 100 => "Excellent",
// >= 70 and < 90 => "Good",
// _ => "Poor",
// };
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string>> GetBand_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_1 = global::System.Linq.Expressions.Expression.Constant("Poor", typeof(string)); // "Poor"
var expr_4 = global::System.Linq.Expressions.Expression.Constant(70, typeof(int)); // 70
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(90, typeof(int)); // 90
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("Good", typeof(string)); // "Good"
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(90, typeof(int)); // 90
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(100, typeof(int)); // 100
var expr_12 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.LessThanOrEqual, 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("Excellent", typeof(string)); // "Excellent"
var expr_15 = global::System.Linq.Expressions.Expression.Condition(expr_9, expr_14, expr_8, typeof(string));
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string>>(expr_15, p_p);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_ProductExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_ProductExt { }
}
// === 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.ProductExt).GetMethod("GetBand", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_ProductExt", "GetBand_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, "AZvl2uoZvjmD4cbWTY61w4EBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T1> __Polyfill_Select_3e61_14_23<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: p => new { p.Name, Band = p.GetBand() }
var i3e6114c23_p_p = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "p");
var i3e6114c23_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6114c23_p_p, typeof(T0).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.Name
var i3e6114c23_expr_2 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductExt).GetMethod("GetBand", 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[] { i3e6114c23_p_p }); // p.GetBand()
var i3e6114c23_expr_3 = typeof(T1).GetConstructors()[0];
var i3e6114c23_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6114c23_expr_3, new global::System.Linq.Expressions.Expression[] { i3e6114c23_expr_1, i3e6114c23_expr_2 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Name"), typeof(T1).GetProperty("Band") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6114c23_expr_0, i3e6114c23_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.Name, Band = p.GetBand() })
// Setup
public static class ProductExt
{
[Expressive]
public static string GetBand(this Product p) => p.StockQuantity switch
{
>= 90 and <= 100 => "Excellent",
>= 70 and < 90 => "Good",
_ => "Poor",
};
}Generated SQL:
SELECT "p"."Name", CASE
WHEN "p"."StockQuantity" >= 90 AND "p"."StockQuantity" <= 100 THEN 'Excellent'
WHEN "p"."StockQuantity" >= 70 AND "p"."StockQuantity" < 90 THEN 'Good'
ELSE 'Poor'
END AS "Band"
FROM "Products" AS "p"when Guards
db
.Products
.Select(p => new { p.Name, Class = p.Classify() })
// Setup
public static class ProductExt
{
[Expressive]
public static string Classify(this Product p) => p.StockQuantity switch
{
4 when p.Category == "Special" => "Special Four",
4 => "Regular Four",
_ => "Other",
};
}SELECT "p"."Name", CASE
WHEN "p"."StockQuantity" = 4 AND "p"."Category" = 'Special' THEN 'Special Four'
WHEN "p"."StockQuantity" = 4 THEN 'Regular Four'
ELSE 'Other'
END AS "Class"
FROM "Products" AS "p"SELECT p."Name", CASE
WHEN p."StockQuantity" = 4 AND p."Category" = 'Special' THEN 'Special Four'
WHEN p."StockQuantity" = 4 THEN 'Regular Four'
ELSE 'Other'
END AS "Class"
FROM "Products" AS pSELECT [p].[Name], CASE
WHEN [p].[StockQuantity] = 4 AND [p].[Category] = N'Special' THEN N'Special Four'
WHEN [p].[StockQuantity] = 4 THEN N'Regular Four'
ELSE N'Other'
END AS [Class]
FROM [Products] AS [p]playground.products.Aggregate([
{
"$project" : {
"Name" : "$Name",
"Class" : {
"$cond" : {
"if" : {
"$and" : [
{
"$eq" : ["$StockQuantity", 4]
},
{
"$eq" : ["$Category", "Special"]
}
]
},
"then" : "Special Four",
"else" : {
"$cond" : {
"if" : {
"$eq" : ["$StockQuantity", 4]
},
"then" : "Regular Four",
"else" : "Other"
}
}
}
},
"_id" : 0
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_ProductExt.Classify_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_ProductExt
{
// [Expressive]
// public static string Classify(this Product p) => p.StockQuantity switch
// {
// 4 when p.Category == "Special" => "Special Four",
// 4 => "Regular Four",
// _ => "Other",
// };
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string>> Classify_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_1 = global::System.Linq.Expressions.Expression.Constant("Other", typeof(string)); // "Other"
var expr_3 = global::System.Linq.Expressions.Expression.Constant(4, typeof(int)); // 4
var expr_2 = global::System.Linq.Expressions.Expression.Equal(expr_0, expr_3);
var expr_4 = global::System.Linq.Expressions.Expression.Constant("Regular Four", typeof(string)); // "Regular Four"
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(4, typeof(int)); // 4
var expr_6 = global::System.Linq.Expressions.Expression.Equal(expr_0, expr_7);
var expr_9 = global::System.Linq.Expressions.Expression.Property(p_p, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product).GetProperty("Category", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.Category
var expr_10 = global::System.Linq.Expressions.Expression.Constant("Special", typeof(string)); // "Special"
var expr_8 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Equal, expr_9, expr_10);
var expr_11 = global::System.Linq.Expressions.Expression.AndAlso(expr_6, expr_8);
var expr_12 = global::System.Linq.Expressions.Expression.Constant("Special Four", typeof(string)); // "Special Four"
var expr_13 = global::System.Linq.Expressions.Expression.Condition(expr_11, expr_12, expr_5, typeof(string));
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product, string>>(expr_13, p_p);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_ProductExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_ProductExt { }
}
// === 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.ProductExt).GetMethod("Classify", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Product) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_ProductExt", "Classify_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, "HV9ofpGne5shEsezzNgVRIEBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T1> __Polyfill_Select_3e61_14_23<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: p => new { p.Name, Class = p.Classify() }
var i3e6114c23_p_p = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "p");
var i3e6114c23_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6114c23_p_p, typeof(T0).GetProperty("Name", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // p.Name
var i3e6114c23_expr_2 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.ProductExt).GetMethod("Classify", 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[] { i3e6114c23_p_p }); // p.Classify()
var i3e6114c23_expr_3 = typeof(T1).GetConstructors()[0];
var i3e6114c23_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6114c23_expr_3, new global::System.Linq.Expressions.Expression[] { i3e6114c23_expr_1, i3e6114c23_expr_2 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Name"), typeof(T1).GetProperty("Class") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6114c23_expr_0, i3e6114c23_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.Name, Class = p.Classify() })
// Setup
public static class ProductExt
{
[Expressive]
public static string Classify(this Product p) => p.StockQuantity switch
{
4 when p.Category == "Special" => "Special Four",
4 => "Regular Four",
_ => "Other",
};
}Generated SQL:
SELECT "p"."Name", CASE
WHEN "p"."StockQuantity" = 4 AND "p"."Category" = 'Special' THEN 'Special Four'
WHEN "p"."StockQuantity" = 4 THEN 'Regular Four'
ELSE 'Other'
END AS "Class"
FROM "Products" AS "p"Type Patterns with Declaration Variables
Type patterns in switch arms produce type checks and casts:
[Expressive]
public static string Describe(this Shape shape) => shape switch
{
Circle c => $"Circle with radius {c.Radius}",
Rectangle r => $"Rectangle {r.Width}x{r.Height}",
_ => "Unknown shape",
};TIP
Declaration variables (the c and r in the example above) are supported in switch arms. The generated expression uses type checks (is) and casts to bind the variable.
Nested Patterns
Patterns can be nested arbitrarily:
db
.Orders
.Select(o => new { o.Id, Tag = o.ClassifyOrder() })
// Setup
public static class OrderExt
{
[Expressive]
public static string ClassifyOrder(this Order o) => o switch
{
{ Customer.Country: "US", Items.Count: >= 10 } => "VIP Order",
{ Customer: not null, Items.Count: >= 5 } => "Standard Order",
_ => "Basic Order",
};
}SELECT "o"."Id", "c"."Country" = 'US' AND "c"."Country" IS NOT NULL, "c"."Id", "l"."Id", "l"."OrderId", "l"."ProductId", "l"."Quantity", "l"."UnitPrice", CASE
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId") >= 10 THEN 1
ELSE 0
END, 1, "l1"."Id", "l1"."OrderId", "l1"."ProductId", "l1"."Quantity", "l1"."UnitPrice", CASE
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l2"
WHERE "o"."Id" = "l2"."OrderId") >= 5 THEN 1
ELSE 0
END
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
LEFT JOIN "LineItems" AS "l" ON "o"."Id" = "l"."OrderId"
LEFT JOIN "LineItems" AS "l1" ON "o"."Id" = "l1"."OrderId"
ORDER BY "o"."Id", "c"."Id", "l"."Id"SELECT o."Id", c."Country" = 'US' AND c."Country" IS NOT NULL, c."Id", l."Id", l."OrderId", l."ProductId", l."Quantity", l."UnitPrice", CASE
WHEN (
SELECT count(*)::int
FROM "LineItems" AS l0
WHERE o."Id" = l0."OrderId") >= 10 THEN TRUE
ELSE FALSE
END, TRUE, l1."Id", l1."OrderId", l1."ProductId", l1."Quantity", l1."UnitPrice", CASE
WHEN (
SELECT count(*)::int
FROM "LineItems" AS l2
WHERE o."Id" = l2."OrderId") >= 5 THEN TRUE
ELSE FALSE
END
FROM "Orders" AS o
INNER JOIN "Customers" AS c ON o."CustomerId" = c."Id"
LEFT JOIN "LineItems" AS l ON o."Id" = l."OrderId"
LEFT JOIN "LineItems" AS l1 ON o."Id" = l1."OrderId"
ORDER BY o."Id", c."Id", l."Id"SELECT [o].[Id], CASE
WHEN [c].[Country] = N'US' AND [c].[Country] IS NOT NULL THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END, [c].[Id], [l].[Id], [l].[OrderId], [l].[ProductId], [l].[Quantity], [l].[UnitPrice], CASE
WHEN (
SELECT COUNT(*)
FROM [LineItems] AS [l0]
WHERE [o].[Id] = [l0].[OrderId]) >= 10 THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END, CAST(1 AS bit), [l1].[Id], [l1].[OrderId], [l1].[ProductId], [l1].[Quantity], [l1].[UnitPrice], CASE
WHEN (
SELECT COUNT(*)
FROM [LineItems] AS [l2]
WHERE [o].[Id] = [l2].[OrderId]) >= 5 THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END
FROM [Orders] AS [o]
INNER JOIN [Customers] AS [c] ON [o].[CustomerId] = [c].[Id]
LEFT JOIN [LineItems] AS [l] ON [o].[Id] = [l].[OrderId]
LEFT JOIN [LineItems] AS [l1] ON [o].[Id] = [l1].[OrderId]
ORDER BY [o].[Id], [c].[Id], [l].[Id]playground.orders.Aggregate([
{
"$project" : {
"_id" : "$_id",
"Tag" : {
"$cond" : {
"if" : {
"$and" : [
{
"$ne" : ["$$ROOT", null]
},
{
"$ne" : ["$Customer", null]
},
{
"$eq" : ["$Customer.Country", "US"]
},
{
"$ne" : ["$Items", null]
},
{
"$gte" : [
{ "$size" : "$Items" },
10
]
}
]
},
"then" : "VIP Order",
"else" : {
"$cond" : {
"if" : {
"$and" : [
{
"$ne" : ["$$ROOT", null]
},
{
"$not" : {
"$eq" : ["$Customer", null]
}
},
{
"$ne" : ["$Items", null]
},
{
"$gte" : [
{ "$size" : "$Items" },
5
]
}
]
},
"then" : "Standard Order",
"else" : "Basic Order"
}
}
}
}
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.ClassifyOrder_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt
{
// [Expressive]
// public static string ClassifyOrder(this Order o) => o switch
// {
// { Customer.Country: "US", Items.Count: >= 10 } => "VIP Order",
// { Customer: not null, Items.Count: >= 5 } => "Standard Order",
// _ => "Basic Order",
// };
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string>> ClassifyOrder_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.Constant("Basic Order", typeof(string)); // "Basic Order"
var expr_2 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order));
var expr_1 = global::System.Linq.Expressions.Expression.NotEqual(p_o, expr_2);
var expr_3 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_7 = global::System.Linq.Expressions.Expression.Constant(null, typeof(object)); // null
var expr_6 = global::System.Linq.Expressions.Expression.Convert(expr_7, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer));
var expr_5 = global::System.Linq.Expressions.Expression.Equal(expr_3, expr_6);
var expr_4 = global::System.Linq.Expressions.Expression.Not(expr_5);
var expr_8 = 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));
var expr_10 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::System.Collections.Generic.ICollection<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem>));
var expr_9 = global::System.Linq.Expressions.Expression.NotEqual(expr_8, expr_10);
var expr_11 = global::System.Linq.Expressions.Expression.Property(expr_8, typeof(global::System.Collections.Generic.ICollection<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem>).GetProperty("Count", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_13 = global::System.Linq.Expressions.Expression.Constant(5, typeof(int)); // 5
var expr_12 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, 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.AndAlso(expr_1, expr_4);
var expr_16 = global::System.Linq.Expressions.Expression.AndAlso(expr_15, expr_14);
var expr_17 = global::System.Linq.Expressions.Expression.Constant("Standard Order", typeof(string)); // "Standard Order"
var expr_18 = global::System.Linq.Expressions.Expression.Condition(expr_16, expr_17, expr_0, typeof(string));
var expr_20 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order));
var expr_19 = global::System.Linq.Expressions.Expression.NotEqual(p_o, expr_20);
var expr_21 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_23 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer));
var expr_22 = global::System.Linq.Expressions.Expression.NotEqual(expr_21, expr_23);
var expr_24 = global::System.Linq.Expressions.Expression.Property(expr_21, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Country", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_26 = global::System.Linq.Expressions.Expression.Constant("US", typeof(string)); // "US"
var expr_25 = global::System.Linq.Expressions.Expression.Equal(expr_24, expr_26);
var expr_27 = global::System.Linq.Expressions.Expression.AndAlso(expr_22, expr_25);
var expr_28 = 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));
var expr_30 = global::System.Linq.Expressions.Expression.Constant(null, typeof(global::System.Collections.Generic.ICollection<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem>));
var expr_29 = global::System.Linq.Expressions.Expression.NotEqual(expr_28, expr_30);
var expr_31 = global::System.Linq.Expressions.Expression.Property(expr_28, typeof(global::System.Collections.Generic.ICollection<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem>).GetProperty("Count", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var expr_33 = global::System.Linq.Expressions.Expression.Constant(10, typeof(int)); // 10
var expr_32 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, 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.AndAlso(expr_19, expr_27);
var expr_36 = global::System.Linq.Expressions.Expression.AndAlso(expr_35, expr_34);
var expr_37 = global::System.Linq.Expressions.Expression.Constant("VIP Order", typeof(string)); // "VIP Order"
var expr_38 = global::System.Linq.Expressions.Expression.Condition(expr_36, expr_37, expr_18, typeof(string));
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string>>(expr_38, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt { }
}
// === ExpressionRegistry.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
internal static class ExpressionRegistry
{
private static Dictionary<nint, LambdaExpression> Build()
{
const BindingFlags allFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
var map = new Dictionary<nint, LambdaExpression>();
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("ClassifyOrder", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderExt", "ClassifyOrder_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, "m/9rAoVVUikWXuWxfqLH9H8BAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T1> __Polyfill_Select_3e61_14_21<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: o => new { o.Id, Tag = o.ClassifyOrder() }
var i3e6114c21_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "o");
var i3e6114c21_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6114c21_p_o, typeof(T0).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var i3e6114c21_expr_2 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("ClassifyOrder", 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[] { i3e6114c21_p_o }); // o.ClassifyOrder()
var i3e6114c21_expr_3 = typeof(T1).GetConstructors()[0];
var i3e6114c21_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6114c21_expr_3, new global::System.Linq.Expressions.Expression[] { i3e6114c21_expr_1, i3e6114c21_expr_2 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Id"), typeof(T1).GetProperty("Tag") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6114c21_expr_0, i3e6114c21_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, Tag = o.ClassifyOrder() })
// Setup
public static class OrderExt
{
[Expressive]
public static string ClassifyOrder(this Order o) => o switch
{
{ Customer.Country: "US", Items.Count: >= 10 } => "VIP Order",
{ Customer: not null, Items.Count: >= 5 } => "Standard Order",
_ => "Basic Order",
};
}Generated SQL:
SELECT "o"."Id", "c"."Country" = 'US' AND "c"."Country" IS NOT NULL, "c"."Id", "l"."Id", "l"."OrderId", "l"."ProductId", "l"."Quantity", "l"."UnitPrice", CASE
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l0"
WHERE "o"."Id" = "l0"."OrderId") >= 10 THEN 1
ELSE 0
END, 1, "l1"."Id", "l1"."OrderId", "l1"."ProductId", "l1"."Quantity", "l1"."UnitPrice", CASE
WHEN (
SELECT COUNT(*)
FROM "LineItems" AS "l2"
WHERE "o"."Id" = "l2"."OrderId") >= 5 THEN 1
ELSE 0
END
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
LEFT JOIN "LineItems" AS "l" ON "o"."Id" = "l"."OrderId"
LEFT JOIN "LineItems" AS "l1" ON "o"."Id" = "l1"."OrderId"
ORDER BY "o"."Id", "c"."Id", "l"."Id"Translation Output
All pattern-matching constructs compile down to nested conditional expressions. The generator produces a chain of ternaries, which each provider maps to its own conditional syntax (SQL CASE WHEN ... THEN ... ELSE ... END, MongoDB $switch/$cond, etc.). The tabs on the samples above let you inspect the exact translation for your target.
WARNING
Keep patterns reasonably simple for translation. Very deeply nested patterns produce complex output that may be harder to debug and could impact query performance.
