Just Add [Projectable]
Decorate any property, method, or constructor with [Projectable] and the source generator does the rest β no boilerplate, no manual expression trees.
Write properties and methods once β use them anywhere in your LINQ queries, translated to efficient SQL automatically.
Without Projectables β the same sub-expression copy-pasted into every query:
// β 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:
// β
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.
| Package | Description |
|---|---|
EntityFrameworkCore.Projectables.Abstractions | The [Projectable] attribute and source generator |
EntityFrameworkCore.Projectables | The EF Core runtime extension |