Skip to content

EF Core ProjectablesFlexible projection magic for EF Core

Write properties and methods once β€” use them anywhere in your LINQ queries, translated to efficient SQL automatically.

At a Glance ​

Without Projectables β€” the same sub-expression copy-pasted into every query:

csharp
// ❌ Repeated 4Γ— in a single query β€” change the formula and hunt down every copy
var orders = dbContext.Orders
    .Where(o => o.Lines.Sum(l => l.Quantity * l.UnitPrice) > 500)
    .OrderByDescending(o => o.Lines.Sum(l => l.Quantity * l.UnitPrice) * (1 + o.TaxRate))
    .Select(o => new
    {
        Total = o.Lines.Sum(l => l.Quantity * l.UnitPrice) * (1 + o.TaxRate),
        Tier  = o.Lines.Sum(l => l.Quantity * l.UnitPrice) > 1000 ? "Premium" : "Standard"
    })
    .ToList();

With Projectables β€” define once on the entity, compose freely, use anywhere:

csharp
// βœ… Business logic lives on the entity β€” queries stay clean
class Order
{
    public decimal TaxRate { get; set; }
    public ICollection<OrderLine> Lines { get; set; }

    [Projectable]
    public decimal Subtotal => Lines.Sum(l => l.Quantity * l.UnitPrice);

    [Projectable]
    public decimal Total => Subtotal * (1 + TaxRate);   // composes ↑

    [Projectable]
    public string Tier => Subtotal switch               // pattern matching β†’ SQL CASE
    {
        > 1000 => "Premium",
        > 250  => "Standard",
        _      => "Basic"
    };
}

var orders = dbContext.Orders
    .Where(o => o.Subtotal > 500)          // β†’ WHERE
    .OrderByDescending(o => o.Total)       // β†’ ORDER BY
    .Select(o => new { o.Total, o.Tier })  // β†’ SELECT
    .ToList();

The properties are inlined into SQL at query time β€” no client-side evaluation, no N+1, no duplicate expressions.

NuGet Packages ​

PackageDescription
EntityFrameworkCore.Projectables.AbstractionsThe [Projectable] attribute and source generator
EntityFrameworkCore.ProjectablesThe EF Core runtime extension

Released under the MIT License.