Skip to content

Quick Start

This guide walks you through a complete end-to-end example — from installing the NuGet packages to seeing the translated output for your provider.

Prerequisites

  • .NET 8 SDK or later (.NET 10 also supported)
  • A LINQ provider. ExpressiveSharp integrates with EF Core, MongoDB, or any IQueryable<T>.

Step 1 — Install the Packages

Install the core package first:

bash
dotnet add package ExpressiveSharp

Then pick the integration that matches your data source:

bash
dotnet add package ExpressiveSharp.EntityFrameworkCore
bash
dotnet add package ExpressiveSharp.MongoDB
bash
# Nothing else — call .AsExpressive() on your IQueryable<T>
PackagePurpose
ExpressiveSharpCore runtime — expression expansion, transformers, IExpressiveQueryable<T>, ExpressionPolyfill (includes Abstractions)
ExpressiveSharp.AbstractionsLightweight — [Expressive] attribute, [ExpressiveFor], IExpressionTreeTransformer, source generator only (no runtime services)
ExpressiveSharp.EntityFrameworkCoreEF Core integration — UseExpressives(), ExpressiveDbSet<T>, Include/ThenInclude, async methods, analyzers and code fixes
ExpressiveSharp.MongoDBMongoDB integration — .AsExpressive() on IMongoCollection<T>, MQL aggregation translation
ExpressiveSharp.EntityFrameworkCore.RelationalExtensionsSQL window functions — ranking (ROW_NUMBER, RANK, DENSE_RANK, NTILE, PERCENT_RANK, CUME_DIST), aggregate (SUM, AVG, COUNT, MIN, MAX), and navigation (LAG, LEAD, FIRST_VALUE, LAST_VALUE, NTH_VALUE) with PARTITION BY / ORDER BY / ROWS|RANGE frame support, plus indexed Select.

Step 2 — Define Your Entities

Add [Expressive] to any property or method whose body you want translated into an expression tree:

csharp
using ExpressiveSharp;

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public string? Email { get; set; }
    public ICollection<Order> Orders { get; set; } = new List<Order>();

    // Computed property — reusable in any query, translated for any provider
    [Expressive]
    public bool IsVip => Orders.Count() > 10;
}

public class Order
{
    public int Id { get; set; }
    public decimal Price { get; set; }
    public int Quantity { get; set; }
    public int CustomerId { get; set; }
    public Customer Customer { get; set; } = null!;

    [Expressive]
    public decimal Total => Price * Quantity;

    // Switch expression — normally illegal in expression trees
    [Expressive]
    public string Grade => Price switch
    {
        >= 100 => "Premium",
        >= 50  => "Standard",
        _      => "Budget",
    };
}

The source generator runs at compile time and emits a companion Expression<TDelegate> for each [Expressive] member — no runtime reflection.

Step 3 — Wire Up Your Provider

csharp
using ExpressiveSharp.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

public class AppDbContext : DbContext
{
    // ExpressiveDbSet<T> lets modern C# syntax flow through DbSet chains
    public ExpressiveDbSet<Customer> Customers => this.ExpressiveSet<Customer>();
    public ExpressiveDbSet<Order> Orders => this.ExpressiveSet<Order>();

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlite("Data Source=app.db")
                  .UseExpressives();  // register [Expressive] expansion
}
csharp
using ExpressiveSharp.MongoDB.Extensions;
using MongoDB.Driver;

var db = new MongoClient("mongodb://localhost:27017").GetDatabase("shop");
var customers = db.GetCollection<Customer>("customers").AsExpressive();
var orders = db.GetCollection<Order>("orders").AsExpressive();
csharp
using ExpressiveSharp;

// Any IQueryable<T> — your own provider, LINQ to Objects, etc.
IQueryable<Customer> raw = GetCustomers();
var customers = raw.AsExpressive();

Step 4 — Write Modern-Syntax Queries

Modern C# syntax — null-conditional operators, switch expressions, pattern matching, and [Expressive] member access — all work directly in the query:

db
    .Orders
    .Where(o => o.Customer.Email != null && o.Total() > 50)
    .Select(o => new { o.Id, Total = o.Total(), Grade = o.Grade(), Email = o.Customer.Email })
    .OrderByDescending(x => x.Total)
    .Take(10)

// Setup
public static class OrderExt
{
    // Computed sum of line items — reusable in any query, translated to SQL/MQL
    [Expressive]
    public static decimal Total(this Order o) => o.Items.Sum(i => i.UnitPrice * i.Quantity);

    // Switch expression over the computed total — illegal in raw expression trees,
    // but [Expressive] expands it into a provider-translatable tree.
    [Expressive]
    public static string Grade(this Order o) => o.Total() switch
    {
        >= 100m => "Premium",
        >= 50m  => "Standard",
        _       => "Budget",
    };
}
.param set @p 10

SELECT "o"."Id", (
    SELECT COALESCE(ef_sum(ef_multiply("l1"."UnitPrice", CAST("l1"."Quantity" AS TEXT))), '0.0')
    FROM "LineItems" AS "l1"
    WHERE "o"."Id" = "l1"."OrderId") AS "Total", CASE
    WHEN ef_compare((
        SELECT COALESCE(ef_sum(ef_multiply("l2"."UnitPrice", CAST("l2"."Quantity" AS TEXT))), '0.0')
        FROM "LineItems" AS "l2"
        WHERE "o"."Id" = "l2"."OrderId"), '100.0') >= 0 THEN 'Premium'
    WHEN ef_compare((
        SELECT COALESCE(ef_sum(ef_multiply("l3"."UnitPrice", CAST("l3"."Quantity" AS TEXT))), '0.0')
        FROM "LineItems" AS "l3"
        WHERE "o"."Id" = "l3"."OrderId"), '50.0') >= 0 THEN 'Standard'
    ELSE 'Budget'
END AS "Grade", "c"."Email"
FROM "Orders" AS "o"
INNER JOIN "Customers" AS "c" ON "o"."CustomerId" = "c"."Id"
WHERE "c"."Email" IS NOT NULL 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"), '50.0') > 0
ORDER BY (
    SELECT COALESCE(ef_sum(ef_multiply("l0"."UnitPrice", CAST("l0"."Quantity" AS TEXT))), '0.0')
    FROM "LineItems" AS "l0"
    WHERE "o"."Id" = "l0"."OrderId") COLLATE EF_DECIMAL DESC
LIMIT @p
-- @p='10'
SELECT o."Id", (
    SELECT COALESCE(sum(l1."UnitPrice" * l1."Quantity"::numeric(18,2)), 0.0)
    FROM "LineItems" AS l1
    WHERE o."Id" = l1."OrderId") AS "Total", CASE
    WHEN (
        SELECT COALESCE(sum(l2."UnitPrice" * l2."Quantity"::numeric(18,2)), 0.0)
        FROM "LineItems" AS l2
        WHERE o."Id" = l2."OrderId") >= 100.0 THEN 'Premium'
    WHEN (
        SELECT COALESCE(sum(l3."UnitPrice" * l3."Quantity"::numeric(18,2)), 0.0)
        FROM "LineItems" AS l3
        WHERE o."Id" = l3."OrderId") >= 50.0 THEN 'Standard'
    ELSE 'Budget'
END AS "Grade", c."Email"
FROM "Orders" AS o
INNER JOIN "Customers" AS c ON o."CustomerId" = c."Id"
WHERE c."Email" IS NOT NULL AND (
    SELECT COALESCE(sum(l."UnitPrice" * l."Quantity"::numeric(18,2)), 0.0)
    FROM "LineItems" AS l
    WHERE o."Id" = l."OrderId") > 50.0
ORDER BY (
    SELECT COALESCE(sum(l0."UnitPrice" * l0."Quantity"::numeric(18,2)), 0.0)
    FROM "LineItems" AS l0
    WHERE o."Id" = l0."OrderId") DESC
LIMIT @p
DECLARE @p int = 10;

SELECT TOP(@p) [o].[Id], (
    SELECT COALESCE(SUM([l1].[UnitPrice] * CAST([l1].[Quantity] AS decimal(18,2))), 0.0)
    FROM [LineItems] AS [l1]
    WHERE [o].[Id] = [l1].[OrderId]) AS [Total], CASE
    WHEN (
        SELECT COALESCE(SUM([l2].[UnitPrice] * CAST([l2].[Quantity] AS decimal(18,2))), 0.0)
        FROM [LineItems] AS [l2]
        WHERE [o].[Id] = [l2].[OrderId]) >= 100.0 THEN N'Premium'
    WHEN (
        SELECT COALESCE(SUM([l3].[UnitPrice] * CAST([l3].[Quantity] AS decimal(18,2))), 0.0)
        FROM [LineItems] AS [l3]
        WHERE [o].[Id] = [l3].[OrderId]) >= 50.0 THEN N'Standard'
    ELSE N'Budget'
END AS [Grade], [c].[Email]
FROM [Orders] AS [o]
INNER JOIN [Customers] AS [c] ON [o].[CustomerId] = [c].[Id]
WHERE [c].[Email] IS NOT NULL AND (
    SELECT COALESCE(SUM([l].[UnitPrice] * CAST([l].[Quantity] AS decimal(18,2))), 0.0)
    FROM [LineItems] AS [l]
    WHERE [o].[Id] = [l].[OrderId]) > 50.0
ORDER BY (
    SELECT COALESCE(SUM([l0].[UnitPrice] * CAST([l0].[Quantity] AS decimal(18,2))), 0.0)
    FROM [LineItems] AS [l0]
    WHERE [o].[Id] = [l0].[OrderId]) DESC
playground.orders.Aggregate([
    {
         "$match" : {
             "$and" : [
                {
                     "Customer.Email" : { "$ne" : null } 
                },
                {
                     "$expr" : {
                         "$gt" : [
                            {
                                 "$sum" : {
                                     "$map" : {
                                         "input" : "$Items",
                                        "as" : "i",
                                        "in" : {
                                             "$multiply" : ["$$i.UnitPrice", "$$i.Quantity"] 
                                        } 
                                    } 
                                } 
                            },
                            { "$numberDecimal" : "50" }
                        ] 
                    } 
                }
            ] 
        } 
    },
    {
         "$project" : {
             "_id" : "$_id",
            "Total" : {
                 "$sum" : {
                     "$map" : {
                         "input" : "$Items",
                        "as" : "i",
                        "in" : {
                             "$multiply" : ["$$i.UnitPrice", "$$i.Quantity"] 
                        } 
                    } 
                } 
            },
            "Grade" : {
                 "$cond" : {
                     "if" : {
                         "$gte" : [
                            {
                                 "$sum" : {
                                     "$map" : {
                                         "input" : "$Items",
                                        "as" : "i",
                                        "in" : {
                                             "$multiply" : ["$$i.UnitPrice", "$$i.Quantity"] 
                                        } 
                                    } 
                                } 
                            },
                            { "$numberDecimal" : "100" }
                        ] 
                    },
                    "then" : "Premium",
                    "else" : {
                         "$cond" : {
                             "if" : {
                                 "$gte" : [
                                    {
                                         "$sum" : {
                                             "$map" : {
                                                 "input" : "$Items",
                                                "as" : "i",
                                                "in" : {
                                                     "$multiply" : ["$$i.UnitPrice", "$$i.Quantity"] 
                                                } 
                                            } 
                                        } 
                                    },
                                    { "$numberDecimal" : "50" }
                                ] 
                            },
                            "then" : "Standard",
                            "else" : "Budget" 
                        } 
                    } 
                } 
            },
            "Email" : "$Customer.Email" 
        } 
    },
    {
         "$sort" : { "Total" : -1 } 
    },
    { "$limit" : 10 }
])
// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.Total_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order.g.cs ===
// <auto-generated/>
#nullable disable

using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;

namespace ExpressiveSharp.Generated
{
    static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt 
    {
        // // Computed sum of line items — reusable in any query, translated to SQL/MQL
        // [Expressive]
        // public static decimal Total(this Order o) => o.Items.Sum(i => i.UnitPrice * i.Quantity);
        static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, decimal>> Total_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression() 
        {
            var p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
            var expr_1 = global::System.Linq.Expressions.Expression.Property(p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Items", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Items
            var p_i_2 = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem), "i"); // i => i.UnitPrice * i.Quantity
            var expr_4 = global::System.Linq.Expressions.Expression.Property(p_i_2, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem).GetProperty("UnitPrice", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // i.UnitPrice
            var expr_6 = global::System.Linq.Expressions.Expression.Property(p_i_2, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem).GetProperty("Quantity", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // i.Quantity
            var expr_5 = global::System.Linq.Expressions.Expression.Convert(expr_6, typeof(decimal));
            var expr_3 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.Multiply, expr_4, expr_5);
            var expr_7 = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem, decimal>>(expr_3, p_i_2);
            var expr_0 = global::System.Linq.Expressions.Expression.Call(global::System.Linq.Enumerable.First(global::System.Linq.Enumerable.Where(typeof(global::System.Linq.Enumerable).GetMethods(global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static), m => m.Name == "Sum" && m.IsGenericMethodDefinition && m.GetGenericArguments().Length == 1 && m.GetParameters().Length == 2 && m.GetParameters()[0].ParameterType.IsGenericType && !m.GetParameters()[0].ParameterType.IsGenericParameter && m.GetParameters()[1].ParameterType.IsGenericType && !m.GetParameters()[1].ParameterType.IsGenericParameter && m.GetParameters()[1].ParameterType.GetGenericArguments()[1] == typeof(decimal))).MakeGenericMethod(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.LineItem)), new global::System.Linq.Expressions.Expression[] { expr_1, expr_7 });
            return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, decimal>>(expr_0, p_o);
        }
    }
}


// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.Grade_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order.g.cs ===
// <auto-generated/>
#nullable disable

using System;
using System.Linq;
using System.Linq.Expressions;
using ExpressiveSharp;
using ExpressiveSharp.EntityFrameworkCore;
using ExpressiveSharp.Docs.PlaygroundModel.Webshop;
using ExpressiveSharp.Docs.Playground.Snippet;

namespace ExpressiveSharp.Generated
{
    static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt 
    {
        // // Switch expression over the computed total — illegal in raw expression trees,
        // // but [Expressive] expands it into a provider-translatable tree.
        // [Expressive]
        // public static string Grade(this Order o) => o.Total() switch
        // {
        //     >= 100m => "Premium",
        //     >= 50m => "Standard",
        //     _ => "Budget",
        // };
        static global::System.Linq.Expressions.Expression<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string>> Grade_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression() 
        {
            var p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
            var expr_0 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("Total", 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.Total()
            var expr_1 = global::System.Linq.Expressions.Expression.Constant("Budget", typeof(string)); // "Budget"
            var expr_3 = global::System.Linq.Expressions.Expression.Constant(50m, typeof(decimal)); // 50m
            var expr_2 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_3);
            var expr_4 = global::System.Linq.Expressions.Expression.Constant("Standard", typeof(string)); // "Standard"
            var expr_5 = global::System.Linq.Expressions.Expression.Condition(expr_2, expr_4, expr_1, typeof(string));
            var expr_7 = global::System.Linq.Expressions.Expression.Constant(100m, typeof(decimal)); // 100m
            var expr_6 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThanOrEqual, expr_0, expr_7);
            var expr_8 = global::System.Linq.Expressions.Expression.Constant("Premium", typeof(string)); // "Premium"
            var expr_9 = global::System.Linq.Expressions.Expression.Condition(expr_6, expr_8, expr_5, typeof(string));
            return global::System.Linq.Expressions.Expression.Lambda<global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, string>>(expr_9, p_o);
        }
    }
}


// === ExpressiveSharp_Docs_Playground_Snippet_OrderExt.Attributes.g.cs ===
// <auto-generated/>

namespace ExpressiveSharp.Generated
{
    [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
    static partial class ExpressiveSharp_Docs_Playground_Snippet_OrderExt { }
}


// === ExpressionRegistry.g.cs ===
// <auto-generated/>
#nullable disable

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;

namespace ExpressiveSharp.Generated
{
    [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
    internal static class ExpressionRegistry
    {
        private static Dictionary<nint, LambdaExpression> Build()
        {
            const BindingFlags allFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
            var map = new Dictionary<nint, LambdaExpression>();
            
            Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("Total", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderExt", "Total_P0_ExpressiveSharp_Docs_PlaygroundModel_Webshop_Order_Expression");
            Register(map, typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("Grade", allFlags, null, new global::System.Type[] { typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order) }, null), "ExpressiveSharp.Generated.ExpressiveSharp_Docs_Playground_Snippet_OrderExt", "Grade_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, "6J+GdN0r/znWxHOArrMAth8CAABfX1NuaXBwZXQuY3M=")]
        internal static global::ExpressiveSharp.IExpressiveQueryable<T0> __Polyfill_OrderByDescending_3e61_17_5<T0, T1>(
            this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
            global::System.Func<T0, T1> __func)
        {
            // Source: x => x.Total
            var i3e6117c5_p_x = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "x");
            var i3e6117c5_expr_0 = global::System.Linq.Expressions.Expression.Property(i3e6117c5_p_x, typeof(T0).GetProperty("Total", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // x.Total
            var __lambda = global::System.Linq.Expressions.Expression.Lambda<global::System.Func<T0, T1>>(i3e6117c5_expr_0, i3e6117c5_p_x);
            return (global::ExpressiveSharp.IExpressiveQueryable<T0>)(object)
                global::ExpressiveSharp.ExpressiveQueryableExtensions.AsExpressive(
                    global::System.Linq.Queryable.OrderByDescending(
                        (global::System.Linq.IQueryable<T0>)(object)source,
                        __lambda));
        }
        [global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "6J+GdN0r/znWxHOArrMAtsABAABfX1NuaXBwZXQuY3M=")]
        internal static global::ExpressiveSharp.IExpressiveQueryable<T1> __Polyfill_Select_3e61_16_5<T0, T1>(
            this global::ExpressiveSharp.IExpressiveQueryable<T0> source,
            global::System.Func<T0, T1> __func)
        {
            // Source: o => new { o.Id, Total = o.Total(), Grade = o.Grade(), Email = o.Customer.Email }
            var i3e6116c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(T0), "o");
            var i3e6116c5_expr_1 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_o, typeof(T0).GetProperty("Id", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Id
            var i3e6116c5_expr_2 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("Total", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(T0) }, null), new global::System.Linq.Expressions.Expression[] { i3e6116c5_p_o }); // o.Total()
            var i3e6116c5_expr_3 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("Grade", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Static, null, new global::System.Type[] { typeof(T0) }, null), new global::System.Linq.Expressions.Expression[] { i3e6116c5_p_o }); // o.Grade()
            var i3e6116c5_expr_5 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_p_o, typeof(T0).GetProperty("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Customer
            var i3e6116c5_expr_4 = global::System.Linq.Expressions.Expression.Property(i3e6116c5_expr_5, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Email", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance));
            var i3e6116c5_expr_6 = typeof(T1).GetConstructors()[0];
            var i3e6116c5_expr_0 = global::System.Linq.Expressions.Expression.New(i3e6116c5_expr_6, new global::System.Linq.Expressions.Expression[] { i3e6116c5_expr_1, i3e6116c5_expr_2, i3e6116c5_expr_3, i3e6116c5_expr_4 }, new global::System.Reflection.MemberInfo[] { typeof(T1).GetProperty("Id"), typeof(T1).GetProperty("Total"), typeof(T1).GetProperty("Grade"), typeof(T1).GetProperty("Email") });
            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, "6J+GdN0r/znWxHOArrMAtoQBAABfX1NuaXBwZXQuY3M=")]
        internal static global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> __Polyfill_Where_3e61_15_5(
            this global::ExpressiveSharp.IExpressiveQueryable<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order> source,
            global::System.Func<global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order, bool> __func)
        {
            // Source: o => o.Customer.Email != null && o.Total() > 50
            var i3e6115c5_p_o = global::System.Linq.Expressions.Expression.Parameter(typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order), "o");
            var i3e6115c5_expr_3 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_p_o, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Order).GetProperty("Customer", global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::System.Reflection.BindingFlags.Instance)); // o.Customer
            var i3e6115c5_expr_2 = global::System.Linq.Expressions.Expression.Property(i3e6115c5_expr_3, typeof(global::ExpressiveSharp.Docs.PlaygroundModel.Webshop.Customer).GetProperty("Email", 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(null, typeof(object)); // null
            var i3e6115c5_expr_4 = global::System.Linq.Expressions.Expression.Convert(i3e6115c5_expr_5, typeof(string));
            var i3e6115c5_expr_1 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.NotEqual, i3e6115c5_expr_2, i3e6115c5_expr_4);
            var i3e6115c5_expr_7 = global::System.Linq.Expressions.Expression.Call(typeof(global::ExpressiveSharp.Docs.Playground.Snippet.OrderExt).GetMethod("Total", 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.Total()
            var i3e6115c5_expr_9 = global::System.Linq.Expressions.Expression.Constant(50, typeof(int)); // 50
            var i3e6115c5_expr_8 = global::System.Linq.Expressions.Expression.Convert(i3e6115c5_expr_9, typeof(decimal));
            var i3e6115c5_expr_6 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.GreaterThan, i3e6115c5_expr_7, i3e6115c5_expr_8);
            var i3e6115c5_expr_0 = global::System.Linq.Expressions.Expression.MakeBinary(global::System.Linq.Expressions.ExpressionType.AndAlso, i3e6115c5_expr_1, i3e6115c5_expr_6);
            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) { }
    }
}

The tabs above show how this exact query translates for each provider. The ?. operator, the [Expressive] Total and Grade members, and the switch expression inside Grade are all compiled into the provider's native query language — no data is loaded into memory for filtering or projection.

Step 5 — Inspect the Generated Query

csharp
// Use ToQueryString() to inspect the SQL without executing
var sql = ctx.Orders
    .Where(o => o.Customer.Email != null)
    .Select(o => new { o.Id, o.Grade })
    .ToQueryString();
Console.WriteLine(sql);
csharp
// ToString() on the queryable yields the aggregation pipeline
var pipeline = orders
    .Where(o => o.Customer.Email != null)
    .Select(o => new { o.Id, o.Grade })
    .ToString();
Console.WriteLine(pipeline);

Next Steps

Released under the MIT License.