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.