diff --git a/404.html b/404.html index 6722a22..d3b890d 100644 --- a/404.html +++ b/404.html @@ -4,7 +4,7 @@
{
# No filter - all people that acted in 3 movies
people(filter: "actorIn.count() == 3") { ... }
# Count only those that match the filter - all people that acted in any movie starting with "Star"
people(filter: "actorIn.count(name.startsWith(\"Star\")) > 0") { ... }
}
List.first(filter?)
- Return the first item from a list. Optionally by a filterList.last(filter?)
- Return the last item from a list. Optionally by a filterList.first(filter?)
/ List.firstOrDefault(filter?)
- Return the first item from a list. Optionally by a filterList.last(filter?)
/ List.lastOrDefault(filter?)
- Return the last item from a list. Optionally by a filterList.take(int)
- Return the first x
itemsList.skip(int)
- Return the items after x
List.orderBy(field)
- Order the list by a given fieldinput PeopleSortInput
{
id: SortDirectionEnum
firstName: SortDirectionEnum
lastName: SortDirectionEnum
dob: SortDirectionEnum
died: SortDirectionEnum
isDeleted: SortDirectionEnum
}
enum SortDirectionEnum {
ASC
DESC
}
To sort the collection you set the fields with a direction:
{
people(sort: [{ lastName: DESC }]) {
lastName
}
}
{
people(sort: [{ dob: ASC }]) {
lastName
}
}
Multiple fields is supported and are taken as ordered
+Multiple fields are supported and are taken as ordered
{
people(sort: [{ dob: ASC }, { lastName: DESC }, { firstName: ASC }]) {
lastName
}
}
You can set a default sort to be applied if there are no sort arguments passed in the query.
@@ -29,7 +29,7 @@schema.ReplaceField("people",
ctx => ctx.People,
"Return a list of people. Optional sorted")
.UseSort(
new Sort<Person>((person) => person.Height, SortDirection.ASC),
new Sort<Person>((person) => person.LastName, SortDirection.ASC)
);
If you use the UseSort()
method (not the attribute) you can pass in an expression which tells the extension which fields to set in the input type. Make sure you use the correct type for the fields collection. You can still set the default sort as well.
schema.ReplaceField("people",
ctx => ctx.People,
"Return a list of people. Optional sorted")
// available sort fields
.UseSort((Person person) => new
{
person.Dob,
person.LastName
},
// Default sort
(Person person) => person.Dob, SortDirectionEnum.DESC);
schema.ReplaceField("people",
ctx => ctx.People,
"Return a list of people. Optional sorted")
// available sort fields
.UseSort((Person person) => new
{
person.Dob,
person.LastName,
manager = person.Manager.Name
},
// Default sort
(Person person) => person.Dob, SortDirectionEnum.DESC);
This will result in only 2 options for sorting.
input PeopleSortInput {
dob: SortDirectionEnum
lastName: SortDirectionEnum
}
schema.UpdateType<Floor>(type => {
type.AddField("floorUrl", "Current floor url")
.Resolve<IFloorUrlService>((floor, srv) => s.BuildFloorPlanUrl(f.SomeRelation.FirstOrDefault().Id));
});
Will extract the f.SomeRelation.FirstOrDefault().Id
expression. That will be fetched in the first expression execution as f.SomeRelation_FirstOrDefault___Id = f.SomeRelation.FirstOrDefault().Id
. So when we rebuild the final expression to also execute service fields it will update the expression to be s.BuildFloorPlanUrl(f.SomeRelation_FirstOrDefault___Id)
.
You may encounter some issues with EF depending on how complex you expressions are. For example pre-6.0 this issue will be hit if you traverse through a relation.
-It is best to keep the expressions used to pass query context data into a service as simple as you can. Remember, your services can also access the DB context or anything else they need via DI.
It is best to keep the expressions used to pass query context data into a service as simple as you can. Remember, your services can also access the DB context or anything else they need via DI.
+If you want to better understand which EF query is being run from which GraphQL operation you can use the ExecutionOptions.BeforeRootFieldExpressionBuild
callback to add the EF TagWith
extension method to the query. Below is an example using the MapGraphQL
ASP.NET helper.
app.UseEndpoints(endpoints =>
{
endpoints.MapGraphQL<DemoContext>(options: new ExecutionOptions
{
BeforeRootFieldExpressionBuild = (exp, op, field) =>
{
if (exp.Type.IsGenericTypeQueryable())
return Expression.Call(typeof(EntityFrameworkQueryableExtensions), nameof(EntityFrameworkQueryableExtensions.TagWith), [exp.Type.GetGenericArguments()[0]], exp, Expression.Constant($"GQL op: {op ?? "n/a"}, field: {field}"));
return exp;
}
});
});