Reusable Query Filters
This recipe shows how to define reusable filtering logic as [Expressive] properties and extension methods, and compose them across multiple queries without duplicating LINQ expressions.
The Pattern
Define your filtering criteria as [Expressive] members that return bool. Use them in Where() clauses exactly as you would any other property. EF Core translates the expanded expression to a SQL WHERE clause.
Example: Active Entity Filter
db
.Customers
.Where(c => c.IsActive())
// Setup
public static class CustomerActiveExt
{
[Expressive]
public static bool IsActive(this Customer c) =>
c.Email != null
&& c.JoinedAt >= new DateTime(2023, 1, 1);
}SELECT "c"."Id", "c"."Country", "c"."Email", "c"."JoinedAt", "c"."Name"
FROM "Customers" AS "c"
WHERE "c"."Email" IS NOT NULL AND "c"."JoinedAt" >= '2023-01-01 00:00:00'SELECT c."Id", c."Country", c."Email", c."JoinedAt", c."Name"
FROM "Customers" AS c
WHERE c."Email" IS NOT NULL AND c."JoinedAt" >= TIMESTAMP '2023-01-01T00:00:00'SELECT [c].[Id], [c].[Country], [c].[Email], [c].[JoinedAt], [c].[Name]
FROM [Customers] AS [c]
WHERE [c].[Email] IS NOT NULL AND [c].[JoinedAt] >= '2023-01-01T00:00:00.0000000'playground.customers.Aggregate([
{
"$match" : {
"Email" : { "$ne" : null },
"JoinedAt" : {
"$gte" : { "$date" : "2023-01-01T00:00:00Z" }
}
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_CustomerActiveExt.IsActive_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_CustomerActiveExt
{
// [Expressive]
// public static bool IsActive(this Customer c) => c.Email != null && c.JoinedAt >= new DateTime(2023, 1, 1);
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, bool>> IsActive_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_2 = 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_1 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.NotEqual, expr_2, expr_3);
var expr_6 = global::System.Linq.Expressions.Expression.Property(p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("JoinedAt", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.JoinedAt
var expr_8 = global::System.Linq.Expressions.Expression.Constant(2023, typeof(int)); // 2023
var expr_9 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var expr_10 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var expr_7 = global::System.Linq.Expressions.Expression.New(typeof(global::System.DateTime).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(int), typeof(int), typeof(int) }, null), expr_8, expr_9, expr_10);
var expr_5 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_6, expr_7, false, typeof(global::System.DateTime).GetMethod("op_GreaterThanOrEqual", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::System.DateTime), typeof(global::System.DateTime) }, null));
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.AndAlso, expr_1, expr_5);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, bool>>(expr_0, p_c);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_CustomerActiveExt.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_CustomerActiveExt { }
}
// === 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.CustomerActiveExt).GetMethod("IsActive", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_CustomerActiveExt", "IsActive_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, "MPshvEF9twAvXsvy9Xe9UYIBAABfX1NuaXBwZXQuY3M=")]
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.IsActive()
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.CustomerActiveExt).GetMethod("IsActive", 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.IsActive()
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.IsActive())
// Setup
public static class CustomerActiveExt
{
[Expressive]
public static bool IsActive(this Customer c) =>
c.Email != null
&& c.JoinedAt >= new DateTime(2023, 1, 1);
}Generated SQL:
SELECT "c"."Id", "c"."Country", "c"."Email", "c"."JoinedAt", "c"."Name"
FROM "Customers" AS "c"
WHERE "c"."Email" IS NOT NULL AND "c"."JoinedAt" >= '2023-01-01 00:00:00'Reuse everywhere:
db
.Customers
.Where(c => c.IsActive() && c.Country == "US")
.Select(c => c.Id)
// Setup
public static class CustomerActiveExt2
{
[Expressive]
public static bool IsActive(this Customer c) =>
c.Email != null
&& c.JoinedAt >= new DateTime(2023, 1, 1);
}SELECT "c"."Id"
FROM "Customers" AS "c"
WHERE "c"."Email" IS NOT NULL AND "c"."JoinedAt" >= '2023-01-01 00:00:00' AND "c"."Country" = 'US'SELECT c."Id"
FROM "Customers" AS c
WHERE c."Email" IS NOT NULL AND c."JoinedAt" >= TIMESTAMP '2023-01-01T00:00:00' AND c."Country" = 'US'SELECT [c].[Id]
FROM [Customers] AS [c]
WHERE [c].[Email] IS NOT NULL AND [c].[JoinedAt] >= '2023-01-01T00:00:00.0000000' AND [c].[Country] = N'US'playground.customers.Aggregate([
{
"$match" : {
"Email" : { "$ne" : null },
"JoinedAt" : {
"$gte" : { "$date" : "2023-01-01T00:00:00Z" }
},
"Country" : "US"
}
},
{
"$project" : { "_v" : "$_id", "_id" : 0 }
}
])// === ExpressiveSharp_Docs_Playground_Snippet_CustomerActiveExt2.IsActive_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_CustomerActiveExt2
{
// [Expressive]
// public static bool IsActive(this Customer c) => c.Email != null && c.JoinedAt >= new DateTime(2023, 1, 1);
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, bool>> IsActive_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_2 = 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_1 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.NotEqual, expr_2, expr_3);
var expr_6 = global::System.Linq.Expressions.Expression.Property(p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("JoinedAt", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.JoinedAt
var expr_8 = global::System.Linq.Expressions.Expression.Constant(2023, typeof(int)); // 2023
var expr_9 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var expr_10 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var expr_7 = global::System.Linq.Expressions.Expression.New(typeof(global::System.DateTime).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(int), typeof(int), typeof(int) }, null), expr_8, expr_9, expr_10);
var expr_5 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_6, expr_7, false, typeof(global::System.DateTime).GetMethod("op_GreaterThanOrEqual", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::System.DateTime), typeof(global::System.DateTime) }, null));
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.AndAlso, expr_1, expr_5);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, bool>>(expr_0, p_c);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_CustomerActiveExt2.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_CustomerActiveExt2 { }
}
// === 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.CustomerActiveExt2).GetMethod("IsActive", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_CustomerActiveExt2", "IsActive_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, "DsycSMkNdv4BbIVBoMKvNrABAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<int> __Polyfill_Select_3e61_14_70(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, int> __func)
{
// Source: c => c.Id
var i3e6114c70_p_c = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer), "c");
var i3e6114c70_expr_0 = global::System.Linq.Expressions.Expression.Property(i3e6114c70_p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Id
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer, int>>(i3e6114c70_expr_0, i3e6114c70_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, "DsycSMkNdv4BbIVBoMKvNoIBAABfX1NuaXBwZXQuY3M=")]
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.IsActive() && c.Country == "US"
var i3e6114c24_p_c = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer), "c");
var i3e6114c24_expr_1 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.CustomerActiveExt2).GetMethod("IsActive", 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.IsActive()
var i3e6114c24_expr_3 = global::System.Linq.Expressions.Expression.Property(i3e6114c24_p_c, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Country", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // c.Country
var i3e6114c24_expr_4 = global::System.Linq.Expressions.Expression.Constant("US", typeof(string)); // "US"
var i3e6114c24_expr_2 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Equal, i3e6114c24_expr_3, i3e6114c24_expr_4);
var i3e6114c24_expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.AndAlso, i3e6114c24_expr_1, i3e6114c24_expr_2);
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.IsActive() && c.Country == "US")
.Select(c => c.Id)
// Setup
public static class CustomerActiveExt2
{
[Expressive]
public static bool IsActive(this Customer c) =>
c.Email != null
&& c.JoinedAt >= new DateTime(2023, 1, 1);
}Generated SQL:
SELECT "c"."Id"
FROM "Customers" AS "c"
WHERE "c"."Email" IS NOT NULL AND "c"."JoinedAt" >= '2023-01-01 00:00:00' AND "c"."Country" = 'US'Example: Parameterized Filters with Extension Methods
Extension methods are ideal for filters that accept parameters:
db
.Orders
.Where(o => o.IsWithinDateRange(new DateTime(2024, 1, 1), new DateTime(2024, 12, 31)))
.Where(o => o.IsHighValue(500m))
// Setup
public static class OrderParamFilters
{
[Expressive]
public static bool IsWithinDateRange(this Order order, DateTime from, DateTime to) =>
order.PlacedAt >= from && order.PlacedAt <= to;
[Expressive]
public static bool IsHighValue(this Order order, decimal threshold) =>
order.Items.Sum(i => i.UnitPrice * i.Quantity) >= threshold;
[Expressive]
public static bool BelongsToCountry(this Order order, string country) =>
order.Customer != null && order.Customer.Country == country;
}SELECT "o"."Id", "o"."CustomerId", "o"."PlacedAt", "o"."Status"
FROM "Orders" AS "o"
WHERE "o"."PlacedAt" >= '2024-01-01 00:00:00' AND "o"."PlacedAt" <= '2024-12-31 00:00:00' AND ef_compare((
SELECT COALESCE(ef_sum(ef_multiply("l"."UnitPrice", CAST("l"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId"), '500.0') >= 0SELECT o."Id", o."CustomerId", o."PlacedAt", o."Status"
FROM "Orders" AS o
WHERE o."PlacedAt" >= TIMESTAMP '2024-01-01T00:00:00' AND o."PlacedAt" <= TIMESTAMP '2024-12-31T00:00:00' AND (
SELECT COALESCE(sum(l."UnitPrice" * l."Quantity"::numeric(18,2)), 0.0)
FROM "LineItems" AS l
WHERE o."Id" = l."OrderId") >= 500.0SELECT [o].[Id], [o].[CustomerId], [o].[PlacedAt], [o].[Status]
FROM [Orders] AS [o]
WHERE [o].[PlacedAt] >= '2024-01-01T00:00:00.0000000' AND [o].[PlacedAt] <= '2024-12-31T00:00:00.0000000' AND (
SELECT COALESCE(SUM([l].[UnitPrice] * CAST([l].[Quantity] AS decimal(18,2))), 0.0)
FROM [LineItems] AS [l]
WHERE [o].[Id] = [l].[OrderId]) >= 500.0playground.orders.Aggregate([
{
"$match" : {
"PlacedAt" : {
"$gte" : { "$date" : "2024-01-01T00:00:00Z" },
"$lte" : { "$date" : "2024-12-31T00:00:00Z" }
}
}
},
{
"$match" : {
"$expr" : {
"$gte" : [
{
"$sum" : {
"$map" : {
"input" : "$Items",
"as" : "i",
"in" : {
"$multiply" : ["$$i.UnitPrice", "$$i.Quantity"]
}
}
}
},
{ "$numberDecimal" : "500" }
]
}
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderParamFilters.IsWithinDateRange_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_System_DateTime_P2_System_DateTime.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_OrderParamFilters
{
// [Expressive]
// public static bool IsWithinDateRange(this Order order, DateTime from, DateTime to) => order.PlacedAt >= from && order.PlacedAt <= to;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, global::System.DateTime, global::System.DateTime, bool>> IsWithinDateRange_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_System_DateTime_P2_System_DateTime_Expression()
{
var p_order = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "order");
var p_from = global::System.Linq.Expressions.Expression.Parameter(typeof(global::System.DateTime), "from");
var p_to = global::System.Linq.Expressions.Expression.Parameter(typeof(global::System.DateTime), "to");
var expr_2 = global::System.Linq.Expressions.Expression.Property(p_order, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("PlacedAt", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // order.PlacedAt
var expr_1 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_2, p_from, false, typeof(global::System.DateTime).GetMethod("op_GreaterThanOrEqual", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::System.DateTime), typeof(global::System.DateTime) }, null));
var expr_4 = global::System.Linq.Expressions.Expression.Property(p_order, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("PlacedAt", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // order.PlacedAt
var expr_3 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.LessThanOrEqual, expr_4, p_to, false, typeof(global::System.DateTime).GetMethod("op_LessThanOrEqual", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::System.DateTime), typeof(global::System.DateTime) }, null));
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.AndAlso, expr_1, expr_3);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, global::System.DateTime, global::System.DateTime, bool>>(expr_0, p_order, p_from, p_to);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderParamFilters.IsHighValue_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_decimal.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_OrderParamFilters
{
// [Expressive]
// public static bool IsHighValue(this Order order, decimal threshold) => order.Items.Sum(i => i.UnitPrice * i.Quantity) >= threshold;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, decimal, bool>> IsHighValue_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_decimal_Expression()
{
var p_order = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "order");
var p_threshold = global::System.Linq.Expressions.Expression.Parameter(typeof(decimal), "threshold");
var expr_2 = global::System.Linq.Expressions.Expression.Property(p_order, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Items", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // order.Items
var p_i_3 = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem), "i"); // i => i.UnitPrice * i.Quantity
var expr_5 = global::System.Linq.Expressions.Expression.Property(p_i_3, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem).GetProperty("UnitPrice", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // i.UnitPrice
var expr_7 = global::System.Linq.Expressions.Expression.Property(p_i_3, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem).GetProperty("Quantity", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // i.Quantity
var expr_6 = global::System.Linq.Expressions.Expression.Convert(expr_7, typeof(decimal));
var expr_4 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Multiply, expr_5, expr_6);
var expr_8 = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem, decimal>>(expr_4, p_i_3);
var expr_1 = global::System.Linq.Expressions.Expression.Call(global::System.Linq.Enumerable.First(global::System.Linq.Enumerable.Where(typeof(global::System.Linq.Enumerable).GetMethods(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static), m => m.Name == "Sum" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 2 && m.GetParameters()[0].ParameterType.IsGenericType && !m.GetParameters()[0].ParameterType.IsGenericParameter && m.GetParameters()[1].ParameterType.IsGenericType && !m.GetParameters()[1].ParameterType.IsGenericParameter && m.GetParameters()[1].ParameterType.GetGenericArguments()[1] == typeof(decimal))).MakeGenericMethod(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem)), new global::System.Linq.Expressions.Expression[] { expr_2, expr_8 });
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_1, p_threshold);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, decimal, bool>>(expr_0, p_order, p_threshold);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderParamFilters.BelongsToCountry_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_string.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_OrderParamFilters
{
// [Expressive]
// public static bool BelongsToCountry(this Order order, string country) => order.Customer != null && order.Customer.Country == country;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string, bool>> BelongsToCountry_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_string_Expression()
{
var p_order = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "order");
var p_country = global::System.Linq.Expressions.Expression.Parameter(typeof(string), "country");
var expr_3 = global::System.Linq.Expressions.Expression.Property(p_order, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // order.Customer
var expr_2 = global::System.Linq.Expressions.Expression.Convert(expr_3, typeof(object));
var expr_5 = global::System.Linq.Expressions.Expression.Constant(null, typeof(object)); // null
var expr_4 = global::System.Linq.Expressions.Expression.Convert(expr_5, typeof(object));
var expr_1 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.NotEqual, expr_2, expr_4);
var expr_8 = global::System.Linq.Expressions.Expression.Property(p_order, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // order.Customer
var expr_7 = global::System.Linq.Expressions.Expression.Property(expr_8, 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_6 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Equal, expr_7, p_country);
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.AndAlso, expr_1, expr_6);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string, bool>>(expr_0, p_order, p_country);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderParamFilters.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderParamFilters { }
}
// === 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.OrderParamFilters).GetMethod("IsWithinDateRange", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), typeof(global::System.DateTime), typeof(global::System.DateTime) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderParamFilters", "IsWithinDateRange_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_System_DateTime_P2_System_DateTime_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderParamFilters).GetMethod("IsHighValue", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), typeof(decimal) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderParamFilters", "IsHighValue_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_decimal_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderParamFilters).GetMethod("BelongsToCountry", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), typeof(string) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderParamFilters", "BelongsToCountry_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_P1_string_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, "zJL7wt6wjnSVrJV0vh+93t8BAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_Where_3e61_16_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool> __func)
{
// Source: o => o.IsHighValue(500m)
var i3e6116c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6116c5_expr_1 = global::System.Linq.Expressions.Expression.Constant(500m, typeof(decimal)); // 500m
var i3e6116c5_expr_0 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderParamFilters).GetMethod("IsHighValue", 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), typeof(decimal) }, null), new global::System.Linq.Expressions.Expression[] { i3e6116c5_p_o, i3e6116c5_expr_1 });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(i3e6116c5_expr_0, i3e6116c5_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Where(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "zJL7wt6wjnSVrJV0vh+93oQBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_Where_3e61_15_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool> __func)
{
// Source: o => o.IsWithinDateRange(new DateTime(2024, 1, 1), new DateTime(2024, 12, 31))
var i3e6115c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6115c5_expr_2 = global::System.Linq.Expressions.Expression.Constant(2024, typeof(int)); // 2024
var i3e6115c5_expr_3 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var i3e6115c5_expr_4 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var i3e6115c5_expr_1 = global::System.Linq.Expressions.Expression.New(typeof(global::System.DateTime).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(int), typeof(int), typeof(int) }, null), i3e6115c5_expr_2, i3e6115c5_expr_3, i3e6115c5_expr_4);
var i3e6115c5_expr_6 = global::System.Linq.Expressions.Expression.Constant(2024, typeof(int)); // 2024
var i3e6115c5_expr_7 = global::System.Linq.Expressions.Expression.Constant(12, typeof(int)); // 12
var i3e6115c5_expr_8 = global::System.Linq.Expressions.Expression.Constant(31, typeof(int)); // 31
var i3e6115c5_expr_5 = global::System.Linq.Expressions.Expression.New(typeof(global::System.DateTime).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(int), typeof(int), typeof(int) }, null), i3e6115c5_expr_6, i3e6115c5_expr_7, i3e6115c5_expr_8);
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderParamFilters).GetMethod("IsWithinDateRange", 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), typeof(global::System.DateTime), typeof(global::System.DateTime) }, null), new global::System.Linq.Expressions.Expression[] { i3e6115c5_p_o, i3e6115c5_expr_1, i3e6115c5_expr_5 });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(i3e6115c5_expr_0, i3e6115c5_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Where(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>)source,
__lambda));
}
}
}
namespace System.Runtime.CompilerServices
{
[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : global::System.Attribute
{
public InterceptsLocationAttribute(int version, string data) { }
}
}db
.Orders
.Where(o => o.IsWithinDateRange(new DateTime(2024, 1, 1), new DateTime(2024, 12, 31)))
.Where(o => o.IsHighValue(500m))
// Setup
public static class OrderParamFilters
{
[Expressive]
public static bool IsWithinDateRange(this Order order, DateTime from, DateTime to) =>
order.PlacedAt >= from && order.PlacedAt <= to;
[Expressive]
public static bool IsHighValue(this Order order, decimal threshold) =>
order.Items.Sum(i => i.UnitPrice * i.Quantity) >= threshold;
[Expressive]
public static bool BelongsToCountry(this Order order, string country) =>
order.Customer != null && order.Customer.Country == country;
}Generated SQL:
SELECT "o"."Id", "o"."CustomerId", "o"."PlacedAt", "o"."Status"
FROM "Orders" AS "o"
WHERE "o"."PlacedAt" >= '2024-01-01 00:00:00' AND "o"."PlacedAt" <= '2024-12-31 00:00:00' AND ef_compare((
SELECT COALESCE(ef_sum(ef_multiply("l"."UnitPrice", CAST("l"."Quantity" AS TEXT))), '0.0')
FROM "LineItems" AS "l"
WHERE "o"."Id" = "l"."OrderId"), '500.0') >= 0TIP
Parameters (from, to, 500m) are captured as provider parameters -- there is no string concatenation or SQL injection risk.
Example: Composing Filters
Build complex filters by composing simpler [Expressive] members:
db
.Orders
.Where(o => o.IsRecentPaidOrder())
// Setup
public static class OrderComposedFilters
{
[Expressive]
public static bool IsPaid(this Order o) => o.Status == OrderStatus.Paid;
[Expressive]
public static bool IsRecent(this Order o) => o.PlacedAt >= new DateTime(2024, 1, 1);
// Composed from simpler [Expressive] members
[Expressive]
public static bool IsRecentPaidOrder(this Order o) => o.IsPaid() && o.IsRecent();
[Expressive]
public static bool IsEligibleForReturn(this Order order) =>
order.Status == OrderStatus.Delivered
&& order.PlacedAt >= new DateTime(2024, 1, 1);
}.param set @Paid 1
SELECT "o"."Id", "o"."CustomerId", "o"."PlacedAt", "o"."Status"
FROM "Orders" AS "o"
WHERE "o"."Status" = @Paid AND "o"."PlacedAt" >= '2024-01-01 00:00:00'-- @Paid='1'
SELECT o."Id", o."CustomerId", o."PlacedAt", o."Status"
FROM "Orders" AS o
WHERE o."Status" = @Paid AND o."PlacedAt" >= TIMESTAMP '2024-01-01T00:00:00'DECLARE @Paid int = 1;
SELECT [o].[Id], [o].[CustomerId], [o].[PlacedAt], [o].[Status]
FROM [Orders] AS [o]
WHERE [o].[Status] = @Paid AND [o].[PlacedAt] >= '2024-01-01T00:00:00.0000000'playground.orders.Aggregate([
{
"$match" : {
"Status" : 1,
"PlacedAt" : {
"$gte" : { "$date" : "2024-01-01T00:00:00Z" }
}
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderComposedFilters.IsPaid_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_OrderComposedFilters
{
// [Expressive]
// public static bool IsPaid(this Order o) => o.Status == OrderStatus.Paid;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>> IsPaid_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("Status", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Status
var expr_2 = global::System.Linq.Expressions.Expression.Field(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus).GetField("Paid", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static)); // OrderStatus.Paid
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Equal, expr_1, expr_2);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(expr_0, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderComposedFilters.IsRecent_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order.g.cs ===
// <auto-generated/>
#nullable disable
using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;
namespace ExpressiveSharp.Generated
{
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderComposedFilters
{
// [Expressive]
// public static bool IsRecent(this Order o) => o.PlacedAt >= new DateTime(2024, 1, 1);
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>> IsRecent_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression()
{
var p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var expr_1 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("PlacedAt", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.PlacedAt
var expr_3 = global::System.Linq.Expressions.Expression.Constant(2024, typeof(int)); // 2024
var expr_4 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var expr_5 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var expr_2 = global::System.Linq.Expressions.Expression.New(typeof(global::System.DateTime).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(int), typeof(int), typeof(int) }, null), expr_3, expr_4, expr_5);
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_1, expr_2, false, typeof(global::System.DateTime).GetMethod("op_GreaterThanOrEqual", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::System.DateTime), typeof(global::System.DateTime) }, null));
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(expr_0, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderComposedFilters.IsRecentPaidOrder_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_OrderComposedFilters
{
// // Composed from simpler [Expressive] members
// [Expressive]
// public static bool IsRecentPaidOrder(this Order o) => o.IsPaid() && o.IsRecent();
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>> IsRecentPaidOrder_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.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderComposedFilters).GetMethod("IsPaid", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), new global::System.Linq.Expressions.Expression[] { p_o }); // o.IsPaid()
var expr_2 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderComposedFilters).GetMethod("IsRecent", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), new global::System.Linq.Expressions.Expression[] { p_o }); // o.IsRecent()
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.AndAlso, expr_1, expr_2);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(expr_0, p_o);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderComposedFilters.IsEligibleForReturn_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_OrderComposedFilters
{
// [Expressive]
// public static bool IsEligibleForReturn(this Order order) => order.Status == OrderStatus.Delivered && order.PlacedAt >= new DateTime(2024, 1, 1);
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>> IsEligibleForReturn_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression()
{
var p_order = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "order");
var expr_2 = global::System.Linq.Expressions.Expression.Property(p_order, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Status", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // order.Status
var expr_3 = global::System.Linq.Expressions.Expression.Field(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus).GetField("Delivered", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static)); // OrderStatus.Delivered
var expr_1 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Equal, expr_2, expr_3);
var expr_5 = global::System.Linq.Expressions.Expression.Property(p_order, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("PlacedAt", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // order.PlacedAt
var expr_7 = global::System.Linq.Expressions.Expression.Constant(2024, typeof(int)); // 2024
var expr_8 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var expr_9 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var expr_6 = global::System.Linq.Expressions.Expression.New(typeof(global::System.DateTime).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(int), typeof(int), typeof(int) }, null), expr_7, expr_8, expr_9);
var expr_4 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_5, expr_6, false, typeof(global::System.DateTime).GetMethod("op_GreaterThanOrEqual", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::System.DateTime), typeof(global::System.DateTime) }, null));
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.AndAlso, expr_1, expr_4);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(expr_0, p_order);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderComposedFilters.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderComposedFilters { }
}
// === 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.OrderComposedFilters).GetMethod("IsPaid", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderComposedFilters", "IsPaid_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderComposedFilters).GetMethod("IsRecent", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderComposedFilters", "IsRecent_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderComposedFilters).GetMethod("IsRecentPaidOrder", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderComposedFilters", "IsRecentPaidOrder_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderComposedFilters).GetMethod("IsEligibleForReturn", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderComposedFilters", "IsEligibleForReturn_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, "2xoKPlGW3KD11HjG1Xd4cn8BAABfX1NuaXBwZXQuY3M=")]
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.IsRecentPaidOrder()
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.OrderComposedFilters).GetMethod("IsRecentPaidOrder", 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.IsRecentPaidOrder()
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.IsRecentPaidOrder())
// Setup
public static class OrderComposedFilters
{
[Expressive]
public static bool IsPaid(this Order o) => o.Status == OrderStatus.Paid;
[Expressive]
public static bool IsRecent(this Order o) => o.PlacedAt >= new DateTime(2024, 1, 1);
// Composed from simpler [Expressive] members
[Expressive]
public static bool IsRecentPaidOrder(this Order o) => o.IsPaid() && o.IsRecent();
[Expressive]
public static bool IsEligibleForReturn(this Order order) =>
order.Status == OrderStatus.Delivered
&& order.PlacedAt >= new DateTime(2024, 1, 1);
}Generated SQL:
.param set @Paid 1
SELECT "o"."Id", "o"."CustomerId", "o"."PlacedAt", "o"."Status"
FROM "Orders" AS "o"
WHERE "o"."Status" = @Paid AND "o"."PlacedAt" >= '2024-01-01 00:00:00'The composed filters are expanded recursively -- IsRecentPaidOrder references IsPaid and IsRecent, which are both expanded to their underlying expressions before translation.
Example: Global Query Filters with EF Core
[Expressive] properties work in EF Core's global query filters (configured in OnModelCreating):
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Active-order global filter using an [Expressive] extension
modelBuilder.Entity<Order>()
.HasQueryFilter(o => o.Status != OrderStatus.Refunded);
// Tenant isolation filter
modelBuilder.Entity<Order>()
.HasQueryFilter(o => o.CustomerId == _currentCustomerId);
}INFO
When using global query filters, ensure that UseExpressives() is configured on your DbContext. The library includes a convention that expands [Expressive] member references in global filters automatically.
// Bypass the global filter when needed
var allOrders = dbContext.Orders
.IgnoreQueryFilters()
.ToList();Example: Specification Pattern
[Expressive] members pair naturally with the Specification pattern:
db
.Orders
.Where(o => o.RequiresAttention())
.Select(o => o.Id)
// Setup
public static class OrderSpecifications
{
[Expressive]
public static bool IsActive(this Order order) =>
order.Status != OrderStatus.Refunded;
[Expressive]
public static bool IsOverdue(this Order order) =>
order.IsActive()
&& order.PlacedAt < new DateTime(2024, 6, 1)
&& order.Status == OrderStatus.Pending;
[Expressive]
public static bool RequiresAttention(this Order order) =>
order.IsOverdue()
|| order.Status == OrderStatus.Pending;
}.param set @Refunded 4
.param set @Pending 0
SELECT "o"."Id"
FROM "Orders" AS "o"
WHERE ("o"."Status" <> @Refunded AND "o"."PlacedAt" < '2024-06-01 00:00:00' AND "o"."Status" = @Pending) OR "o"."Status" = @Pending-- @Refunded='4'
-- @Pending='0'
SELECT o."Id"
FROM "Orders" AS o
WHERE (o."Status" <> @Refunded AND o."PlacedAt" < TIMESTAMP '2024-06-01T00:00:00' AND o."Status" = @Pending) OR o."Status" = @PendingDECLARE @Refunded int = 4;
DECLARE @Pending int = 0;
SELECT [o].[Id]
FROM [Orders] AS [o]
WHERE ([o].[Status] <> @Refunded AND [o].[PlacedAt] < '2024-06-01T00:00:00.0000000' AND [o].[Status] = @Pending) OR [o].[Status] = @Pendingplayground.orders.Aggregate([
{
"$match" : {
"$or" : [
{
"$and" : [
{
"Status" : { "$ne" : 4 }
},
{
"PlacedAt" : {
"$lt" : { "$date" : "2024-06-01T00:00:00Z" }
}
},
{ "Status" : 0 }
]
},
{ "Status" : 0 }
]
}
},
{
"$project" : { "_v" : "$_id", "_id" : 0 }
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderSpecifications.IsActive_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_OrderSpecifications
{
// [Expressive]
// public static bool IsActive(this Order order) => order.Status != OrderStatus.Refunded;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>> IsActive_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression()
{
var p_order = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "order");
var expr_1 = global::System.Linq.Expressions.Expression.Property(p_order, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Status", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // order.Status
var expr_2 = global::System.Linq.Expressions.Expression.Field(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus).GetField("Refunded", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static)); // OrderStatus.Refunded
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.NotEqual, expr_1, expr_2);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(expr_0, p_order);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderSpecifications.IsOverdue_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_OrderSpecifications
{
// [Expressive]
// public static bool IsOverdue(this Order order) => order.IsActive() && order.PlacedAt < new DateTime(2024, 6, 1) && order.Status == OrderStatus.Pending;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>> IsOverdue_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression()
{
var p_order = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "order");
var expr_2 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderSpecifications).GetMethod("IsActive", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), new global::System.Linq.Expressions.Expression[] { p_order }); // order.IsActive()
var expr_4 = global::System.Linq.Expressions.Expression.Property(p_order, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("PlacedAt", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // order.PlacedAt
var expr_6 = global::System.Linq.Expressions.Expression.Constant(2024, typeof(int)); // 2024
var expr_7 = global::System.Linq.Expressions.Expression.Constant(6, typeof(int)); // 6
var expr_8 = global::System.Linq.Expressions.Expression.Constant(1, typeof(int)); // 1
var expr_5 = global::System.Linq.Expressions.Expression.New(typeof(global::System.DateTime).GetConstructor(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance, null, new global::System.Type[] { typeof(int), typeof(int), typeof(int) }, null), expr_6, expr_7, expr_8);
var expr_3 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.LessThan, expr_4, expr_5, false, typeof(global::System.DateTime).GetMethod("op_LessThan", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::System.DateTime), typeof(global::System.DateTime) }, null));
var expr_1 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.AndAlso, expr_2, expr_3);
var expr_10 = global::System.Linq.Expressions.Expression.Property(p_order, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Status", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // order.Status
var expr_11 = global::System.Linq.Expressions.Expression.Field(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus).GetField("Pending", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static)); // OrderStatus.Pending
var expr_9 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Equal, expr_10, expr_11);
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.AndAlso, expr_1, expr_9);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(expr_0, p_order);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderSpecifications.RequiresAttention_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_OrderSpecifications
{
// [Expressive]
// public static bool RequiresAttention(this Order order) => order.IsOverdue() || order.Status == OrderStatus.Pending;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>> RequiresAttention_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression()
{
var p_order = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "order");
var expr_1 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderSpecifications).GetMethod("IsOverdue", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), new global::System.Linq.Expressions.Expression[] { p_order }); // order.IsOverdue()
var expr_3 = global::System.Linq.Expressions.Expression.Property(p_order, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Status", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // order.Status
var expr_4 = global::System.Linq.Expressions.Expression.Field(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus).GetField("Pending", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static)); // OrderStatus.Pending
var expr_2 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Equal, expr_3, expr_4);
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.OrElse, expr_1, expr_2);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(expr_0, p_order);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderSpecifications.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderSpecifications { }
}
// === 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.OrderSpecifications).GetMethod("IsActive", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderSpecifications", "IsActive_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderSpecifications).GetMethod("IsOverdue", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderSpecifications", "IsOverdue_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderSpecifications).GetMethod("RequiresAttention", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderSpecifications", "RequiresAttention_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, "clAPRShhGEyVDe8+DIQHiKEBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<int> __Polyfill_Select_3e61_14_55(
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 i3e6114c55_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6114c55_expr_0 = global::System.Linq.Expressions.Expression.Property(i3e6114c55_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>>(i3e6114c55_expr_0, i3e6114c55_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, "clAPRShhGEyVDe8+DIQHiH8BAABfX1NuaXBwZXQuY3M=")]
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.RequiresAttention()
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.OrderSpecifications).GetMethod("RequiresAttention", 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.RequiresAttention()
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.RequiresAttention())
.Select(o => o.Id)
// Setup
public static class OrderSpecifications
{
[Expressive]
public static bool IsActive(this Order order) =>
order.Status != OrderStatus.Refunded;
[Expressive]
public static bool IsOverdue(this Order order) =>
order.IsActive()
&& order.PlacedAt < new DateTime(2024, 6, 1)
&& order.Status == OrderStatus.Pending;
[Expressive]
public static bool RequiresAttention(this Order order) =>
order.IsOverdue()
|| order.Status == OrderStatus.Pending;
}Generated SQL:
.param set @Refunded 4
.param set @Pending 0
SELECT "o"."Id"
FROM "Orders" AS "o"
WHERE ("o"."Status" <> @Refunded AND "o"."PlacedAt" < '2024-06-01 00:00:00' AND "o"."Status" = @Pending) OR "o"."Status" = @PendingAll specification methods are expanded recursively -- RequiresAttention calls IsOverdue, which calls IsActive. The entire chain becomes a flat WHERE clause.
Using Filters with ExpressiveDbSet
With ExpressiveDbSet<T>, you can combine [Expressive] filters with inline modern syntax:
db
.Orders
.Where(o => o.IsActive() && o.Customer.Country == "US")
.Select(o => new
{
o.Id,
StatusLabel = o.Status switch
{
OrderStatus.Paid => "Paid",
OrderStatus.Pending => "Pending",
_ => "Other"
}
})
// Setup
public static class OrderActiveForDbSet
{
[Expressive]
public static bool IsActive(this Order order) =>
order.Status != OrderStatus.Refunded;
}.param set @Paid 1
.param set @Pending 0
.param set @Refunded 4
SELECT "o"."Id", CASE
WHEN "o"."Status" = @Paid THEN 'Paid'
WHEN "o"."Status" = @Pending THEN 'Pending'
ELSE 'Other'
END AS "StatusLabel"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "o"."Status" <> @Refunded AND "c"."Country" = 'US'-- @Paid='1'
-- @Pending='0'
-- @Refunded='4'
SELECT o."Id", CASE
WHEN o."Status" = @Paid THEN 'Paid'
WHEN o."Status" = @Pending THEN 'Pending'
ELSE 'Other'
END AS "StatusLabel"
FROM "Orders" AS o
INNER JOIN "Customers" AS c ON o."CustomerId" = c."Id"
WHERE o."Status" <> @Refunded AND c."Country" = 'US'DECLARE @Paid int = 1;
DECLARE @Pending int = 0;
DECLARE @Refunded int = 4;
SELECT [o].[Id], CASE
WHEN [o].[Status] = @Paid THEN N'Paid'
WHEN [o].[Status] = @Pending THEN N'Pending'
ELSE N'Other'
END AS [StatusLabel]
FROM [Orders] AS [o]
INNER JOIN [Customers] AS [c] ON [o].[CustomerId] = [c].[Id]
WHERE [o].[Status] <> @Refunded AND [c].[Country] = N'US'playground.orders.Aggregate([
{
"$match" : {
"Status" : { "$ne" : 4 },
"Customer.Country" : "US"
}
},
{
"$project" : {
"_id" : "$_id",
"StatusLabel" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 1]
},
"then" : "Paid",
"else" : {
"$cond" : {
"if" : {
"$eq" : ["$Status", 0]
},
"then" : "Pending",
"else" : "Other"
}
}
}
}
}
}
])// === ExpressiveSharp_Docs_Playground_Snippet_OrderActiveForDbSet.IsActive_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_OrderActiveForDbSet
{
// [Expressive]
// public static bool IsActive(this Order order) => order.Status != OrderStatus.Refunded;
static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>> IsActive_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression()
{
var p_order = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "order");
var expr_1 = global::System.Linq.Expressions.Expression.Property(p_order, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Status", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // order.Status
var expr_2 = global::System.Linq.Expressions.Expression.Field(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus).GetField("Refunded", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static)); // OrderStatus.Refunded
var expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.NotEqual, expr_1, expr_2);
return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(expr_0, p_order);
}
}
}
// === ExpressiveSharp_Docs_Playground_Snippet_OrderActiveForDbSet.Attributes.g.cs ===
// <auto-generated/>
namespace ExpressiveSharp.Generated
{
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderActiveForDbSet { }
}
// === 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.OrderActiveForDbSet).GetMethod("IsActive", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderActiveForDbSet", "IsActive_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, "TIpck8hPSLOT9AYEb1m1XcABAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<T1> __Polyfill_Select_3e61_16_5<T0, T1>(
this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
global::System.Func<T0, T1> __func)
{
// Source: o => new { o.Id, StatusLabel = o.Status switch { OrderStatus.Paid => "Paid", OrderStatus.Pending => "Pending", _ => "Other" } }
var i3e6116c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "o");
var i3e6116c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_o, typeof(T0).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
var i3e6116c5_expr_2 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_o, typeof(T0).GetProperty("Status", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Status
var i3e6116c5_expr_3 = global::System.Linq.Expressions.Expression.Constant("Other", typeof(string)); // "Other"
var i3e6116c5_expr_5 = global::System.Linq.Expressions.Expression.Field(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus).GetField("Pending", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static)); // OrderStatus.Pending
var i3e6116c5_expr_4 = global::System.Linq.Expressions.Expression.Equal(i3e6116c5_expr_2, i3e6116c5_expr_5);
var i3e6116c5_expr_6 = global::System.Linq.Expressions.Expression.Constant("Pending", typeof(string)); // "Pending"
var i3e6116c5_expr_7 = global::System.Linq.Expressions.Expression.Condition(i3e6116c5_expr_4, i3e6116c5_expr_6, i3e6116c5_expr_3, typeof(string));
var i3e6116c5_expr_9 = global::System.Linq.Expressions.Expression.Field(null, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.OrderStatus).GetField("Paid", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static)); // OrderStatus.Paid
var i3e6116c5_expr_8 = global::System.Linq.Expressions.Expression.Equal(i3e6116c5_expr_2, i3e6116c5_expr_9);
var i3e6116c5_expr_10 = global::System.Linq.Expressions.Expression.Constant("Paid", typeof(string)); // "Paid"
var i3e6116c5_expr_11 = global::System.Linq.Expressions.Expression.Condition(i3e6116c5_expr_8, i3e6116c5_expr_10, i3e6116c5_expr_7, typeof(string));
var i3e6116c5_expr_12 = typeof(T1).GetConstructors()[0];
var i3e6116c5_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6116c5_expr_12, new global::System.Linq.Expressions.Expression[] { i3e6116c5_expr_1, i3e6116c5_expr_11 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Id"), typeof(T1).GetProperty("StatusLabel") });
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6116c5_expr_0, i3e6116c5_p_o);
return (global::ExpressiveSharp.IExpressiveQueryable<T1>)(object)
global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Select(
(global::System.Linq.IQueryable<T0>)(object)source,
__lambda));
}
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "TIpck8hPSLOT9AYEb1m1XYQBAABfX1NuaXBwZXQuY3M=")]
internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_Where_3e61_15_5(
this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool> __func)
{
// Source: o => o.IsActive() && o.Customer.Country == "US"
var i3e6115c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
var i3e6115c5_expr_1 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderActiveForDbSet).GetMethod("IsActive", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), new global::System.Linq.Expressions.Expression[] { i3e6115c5_p_o }); // o.IsActive()
var i3e6115c5_expr_4 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Customer
var i3e6115c5_expr_3 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_expr_4, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Country", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
var i3e6115c5_expr_5 = global::System.Linq.Expressions.Expression.Constant("US", typeof(string)); // "US"
var i3e6115c5_expr_2 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Equal, i3e6115c5_expr_3, i3e6115c5_expr_5);
var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.AndAlso, i3e6115c5_expr_1, i3e6115c5_expr_2);
var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool>>(i3e6115c5_expr_0, i3e6115c5_p_o);
return global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
global::System.Linq.Queryable.Where(
(global::System.Linq.IQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order>)source,
__lambda));
}
}
}
namespace System.Runtime.CompilerServices
{
[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]
file sealed class InterceptsLocationAttribute : global::System.Attribute
{
public InterceptsLocationAttribute(int version, string data) { }
}
}db
.Orders
.Where(o => o.IsActive() && o.Customer.Country == "US")
.Select(o => new
{
o.Id,
StatusLabel = o.Status switch
{
OrderStatus.Paid => "Paid",
OrderStatus.Pending => "Pending",
_ => "Other"
}
})
// Setup
public static class OrderActiveForDbSet
{
[Expressive]
public static bool IsActive(this Order order) =>
order.Status != OrderStatus.Refunded;
}Generated SQL:
.param set @Paid 1
.param set @Pending 0
.param set @Refunded 4
SELECT "o"."Id", CASE
WHEN "o"."Status" = @Paid THEN 'Paid'
WHEN "o"."Status" = @Pending THEN 'Pending'
ELSE 'Other'
END AS "StatusLabel"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "o"."Status" <> @Refunded AND "c"."Country" = 'US'See Modern Syntax in LINQ Chains for more on this approach.
Tips
Compose at the member level
Compose filters inside [Expressive] members rather than chaining multiple .Where() calls. This creates more reusable building blocks.
Name clearly
Use names that express business intent (IsEligibleForRefund) rather than technical details (HasRefundDateNullAndStatusIsComplete).
Prefer entity-level properties for entity-specific filters
Use extension methods for cross-entity or parameterized filters.
Keep filters pure
Filter members should only read data, never modify it. Everything in the body must be translatable by your provider.
See Also
- Computed Entity Properties -- building blocks for filter composition
- Scoring and Classification -- combine filters with classification logic
- Nullable Navigation Properties -- filters that guard against null navigation
