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.
- 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.
- 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). Projectable
s 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()
});
...
}
}