Skip to main content

Reusing Linq Expressions

Computed properties don't work with most Linq providers out of the box. Dave Glick has a great related post on Computed Properties and EntityFramework.

Here's a list of various libraries that can help

Most the these libraries work in a similar ways - examples below are using the syntax from EntityFrameworkCore.Projectables.

  1. Either globally register the library when registering the context
services.AddDbContext<DemoContext>(opt =>
opt.UseSqlite("Filename=demo.db")
.UseProjectables()
);

or enable it per expression.

dbContext.People
.ExpandProjectables()
.Select(x => x.Age())

If you go down the route of registering it per query then you'll need to override the resolve method on the relevant fields on the EQL Schema.

  1. Add an expression bodied function to the entity class or helper class (generally be static or instance) and mark it using an attribute.
[Projectable]
[GraphQLField]
public static int Age(this Person person) => (int)((DateTime.Now - person.Dob).TotalDays / 365);

Some libraries will automatically convert this to an expression property using Source Generators (EFC.Projectables, Expressionfy) or reflection/decompilation (Delegate Decompiler), yet others require you to provide both the method and expression yourself (Nein Linq).

This field is now available to queries (exposed via the [GraphQLField] attribute). Projectables provide reuse of common expression that can also be used outside on EntityGraphQL or in your mutations as well.

public class PeopleMutations
{
[GraphQLMutation("Add a new person to the system")]
public Expression<Func<DemoContext, Person>> UpdatePerson(DemoContext db, int id, string firstName, string lastName)
{
var person = db.People.Select(p => {
p.FirstName,
p.LastName,
p.Age()
});

...
}
}