Bot releases are visible (Hide)
ctx => ctx.People.FirstOrDefault(filter)
EntityGraphQL treats that as a ListToSingle field and will build a full expression similar to ctx => ctx.People.Where(filter).Select(x => new {...}).FirstOrDefault()
to avoid over fetching when using EntityFramework. Previously EntityGraphQL would try to break up and rebuild expressions.methods it didn't know how to. It now correctly only tries this optimization on First
, FirstOrDefault
, Single
, SingleOrDefault
, Last
& LastOrDefault
from Queryable
& Enumerable
Published by lukemurray 7 months ago
UseGraphQLWebSockets
no longer returns 400
if the request is not a web socket request. Allowing the request to get passed to the next handlers. This allows you to have the same endpoint for queries/mutations and subscriptions.GraphQLCollectionToSingleField
to better support customisation in custom directivesfield.Resolve<TService, ...>()
to replace ResolveWithService<>()
. Recommended to use Resolve()
. Release 5.3 will mark ResolveWithService
as deprecated and release 6.0 will remove them.field.ResolveBulk<TService, TKey, TResult>()
to allow you to use services to bulk load data to avoid multiple calls to a service resolve expression that may call an external service in a list result. Exampleschema.AddEnum<TEnum>(typeName, description)
to the schema building APInet8.0
as a target for EntityGraphQL.AspNet projectvar schema = SchemaBuilder.FromObject<MyContext>();
schema.UpdateType<Project>(type =>
{
type.ReplaceField("createdBy", "Get user that created it")
// normal service to fetch the User object for creator of the Project type
.ResolveWithService<UserService>((proj, users) => users.GetUserById(proj.CreatedById))
// Bulk service used to fetch many User objects
.ResolveBulk<UserService, int, User>(proj => proj.CreatedById, (ids, srv) => srv.GetAllUsers(ids));
});
If you have a query like
{
# ResolveBulk
projects {
# project fields
name
id
# service field - resolved with ResolveBulk expression for all Projects loaded
createdBy {
name
}
}
# ResolveWithService
project(id: 78) {
# project fields
name
id
# service field - resolved with ResolveWithService expression for the single project loaded
createdBy {
name
}
}
}
Instead of calling users.GetUserById()
for each project to resolve createdBy { name }
, EntityGraphQL will build a list of keys using the proj => proj.CreatedById
expression from the list of projects and then call the (ids, srv) => srv.GetAllUsers(ids)
expression once for the whole list of projects in the results. See updated documentation for further details.
SchemaBuilder
. Previously they would fail.field.ResolveBulk<TService, TKey, TResult>()
First()
as friends (List to single pattern). E.g. (ctx, service) => ctx.SomeList.First(i => i.Thing == service.Other)
int
style fields against float
style fields in the filter expressionSchemaBuilderOptions
with a mutation method that has a list argument. The argument input type was not being correctly added to the schema. Not an issue if you were already adding the type manually[GraphQLField]
Published by lukemurray 9 months ago
Fix #337 - Description attribute accidentally updating name instead of description
Published by lukemurray 11 months ago
OneOf
directive with ArgumentHelper.Required<T>()
in a query field argument.Published by lukemurray 11 months ago
Guid
or DateTime
when requiredvar schema = SchemaBuilder.FromObject<MyContext>();
schema.AddType<ExternalData>("ExternalData").AddAllFields();
schema.UpdateType<ExternalData>(ed =>
{
// connect back to the MyContext types
ed.AddField("movie", "Get movie")
// here FirstOrDefault() goes from list -> single
.ResolveWithService<MyContext>((ed, db) => db.Movies.Where(m => m.Id == ed.Id).FirstOrDefault());
});
schema.Query().AddField("externalData", "Get Data")
.ResolveWithService<ExternalDataService>((p, srv) => srv.GetData());
In the above case if you select
{
externalData {
movie { director { name } }
}
}
The movie field will have the selection inserted allowing EF to resolve fields without lazy loading turned on. Without this the m.Director.Name
would also be null
as no relation was included. e.g.
db.Movies.Where(m => m.Id == ed.Id)
.Select(m => new [
director = new {
name = m.Director.Name
}
])
.FirstOrDefault();
Published by lukemurray about 1 year ago
Published by lukemurray about 1 year ago
Make sure to check out the changes 5.0.0-beta1
IField.AddExtension
now returns the IField
UseSort()
field extension now can take a list of default sort fields e.g.Broadcaster
(inbuilt IObservable<TType>
you can use for subscriptions) now has a OnUnsubscribe
callbackschema.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)
);
SchemaBuilderOptions
now has a OnFieldCreated
callback to make changes to fields as SchemaBuilder
is building the schema..contains(string)
, .startsWith(string)
, .endsWith(string)
& .toLower()
/ .toUpper()
string methods now available in the filter argument expression.Published by lukemurray over 1 year ago
EntityGraphQL.AspNet
now targets net6.0
and net7.0
, dropping tagets netcoreapp3.1
or net5.0
. You can still use the base EntityGraphQL
library with older targets.IExposableException
has been removed. Use SchemaBuilderSchemaOptions.AllowedExceptions
or the new AllowedExceptionAttribute
to define which exceptions are rendered into the resultsnull
for the ClaimsPrincipal
in ExecuteRequest()
would skip any authorization checks. All authorization checks are now done regardless of the ClaimsPrincipal
value. Meaning null
will fail if there is fields requiring authorization.IDirectiveProcessor
interface has changed. See upgrade docs for changesSchemaBuilderMethodOptions
removed, see updated properties on SchemaBuilderOptions
and upgrade docs. This was because you can also now add methods as query fields with GraphQLFieldAttribute
SchemaBuilderOptions.AutoCreateInputTypes
now defaults to true
. Meaning in SchemaBuilder
when adding mutations etc any complex types will be added to the schema if they are not there already.GraphQLValidator
is no longer magically added to your method fields (mutations/subscriptions). If you wish to use it please register it in your services. There is a new helper method in EntityGraphQL.AspNet AddGraphQLValidator()
. This means you can implement and register your own implementation.SchemaProvider.ExecuteRequest
& SchemaProvider.ExecuteRequestAsync
have been renamed to ExecuteRequestWithContext
& ExecuteRequestWithContextAsync
. The schema context instance provided will be used for all context references within that query.SchemaProvider.ExecuteRequest
& SchemaProvider.ExecuteRequestAsync
which take no schema context instance as an argument. The context will be fetched from the provided ServiceProvider
meaning the lifetime rules are adhered to - e.g. ServiceLifetime.Transient
is now correctly used. This is the perferred way to execute a queryEntityGraphQL
(the core library) targets both netstandard2.1
& net6
. netstandard2.1
will be dropped around the time of net8.0
being released.GraphQLFieldAttribute
to allow you to rename fields in the schema as well as mark methods as fields in the schema. Method parameters will become field arguments in the same way as mutation methods. See updated docs for more information.DescriptionAttribute
and GraphQLFieldAttribute
to use different field name in the schema and set a descriptionGraphQLInputTypeAttribute
. Whereas GraphQLArgumentsAttribute
flattens the types properties into the schema, GraphQLInputTypeAttribute
assumes the type is an input type and uses that as the schema argumentGraphQLValidator
by implementing (and registering) IGraphQLValidator
options.BeforeExecuting
callback to allow modification of the expression before executionAddPossibleType()
when some of the types have already been added to the schemaExecutionOptions
passed into IApplicationBuilder.UseGraphQLWebSockets()
are now used when executing the queries for the subscriptionMyClass<OtherClass>
will become input MyClassOtherClass {}
IQueryable
/DbContext
fieldsPublished by lukemurray over 1 year ago
null
will be returned if the result is null
. If the return type is non-nullable an empty List<T>
will be returned.public class UserDbContextNonNullable
{
// empty list will be returned if UserIds resolves to null. If you use nullable types you can control with the ? operator (to return null)
[GraphQLNotNull]
public List<string> UserIds { get; set; }
}
RuntimeTypeJsonConverter
ResolveWithService
being called twice due to Expression.Condition
if the field is a list and at the root level of the Query typePublished by lukemurray almost 2 years ago
Published by lukemurray almost 2 years ago
IsDevelopment == false
as users not be able to modify the exceptions being thrown in order to have them implement IExposableException
. Exceptions may be allowed with an exact type match, or allowed including all types that inherit itPublished by lukemurray almost 2 years ago
{ myList { myEdges: edges { .. } } }
previously would failPublished by lukemurray about 2 years ago
ToList
expression built to resolve list expressionsUseFilter()
filter
and UseSort()
sort
field arguments were incorrectly being marked as required in schema introspectionUseSort()
not appearing in the schema as default valuesPublished by lukemurray about 2 years ago
When running in development (read via IWebHostEnvironment.IsEnvironment("Development")
or when manually creating SchemaProvider
), messages of exceptions will not be dumped out into the 'errors' field of a query result, unless they implement the newly created (and empty) interface IExposableException
.
System.Text.Json
doesn't support the serialization of polymorphic type hierarchies. EntityGraphQL now registers a RuntimeTypeJsonConverter
class as part of the DefaultGraphQLResponseSerializer
Published by lukemurray about 2 years ago
myItem(id: Int!) @include(...) { ... }
)TargetInvocationException
will now be unwrappedTask<>
. Note that the way that queries expressions are built you may still encounter issues with async
fields not at the root query level. Please open an issue if you doPublished by lukemurray about 2 years ago
application/json; charset=utf-8
content typePublished by lukemurray about 2 years ago
IFieldExtension.ProcessExpressionSelection
now takes a ParameterExpression? argumentParam
argument which is the argument parameter used at execution time (if there is one). Relating to #235Published by lukemurray about 2 years ago
DateTimeOffset
is now added as a default scalar type in schema creation. It is a very common used type in EF contexts and trips up new users. If you previously were adding it as a scalar type you no longer need to. Or if you'd like to add it differently (like map it to Date) you canservices.AddGraphQLSchema<DemoContext>(options =>
{
options.PreBuildSchemaFromContext = (schema) =>
{
schema.RemoveType<DateTimeOffset>();
// add it how you want
};
});
AddMutationsFrom
and friends now take an optional SchemaBuilderMethodOptions
options object to configure how mutations are built, following the SchemaBuilderOptions
used elsewhere. See updated docs. Important defaults:bool AutoCreateInputTypes = true; // Any input types seen will be added to the schema
bool AddNonAttributedMethods = false; // GraphQLMutationAttributes are still required by default
bool AutoCreateNewComplexTypes = true; // Return types of mutations will be added to the schema
SchemaBuilderOptions.IgnoreTypes
Now uses Type
instead of string
. It is a HashSet<Type>
now to avoid confusion ofwhich name to use (full name space or not)ProcessExpressionSelection
used in Field Extentions now takes Dictionary<IFieldKey, CompiledField>
for the selectionExpressions
parameter. IFieldKey
is the field name and the schema type the field belongs too. Helps when dealing with inline fragments/union types where we may have multiple fields with the same name from different types.MutationArgumentsAttribute
renamed to GraphQLArgumentsAttribute
and is used with subscriptions or mutaiton method argumentsEntityGraphQL
only targets netstandard2.1
as we do not need to multi-target and this still supports a large dotnet base (3.1+)ArgumentHelper.Required<>()
field argument is non-nullMutationArgumentsAttribute
) parameters fail if called without variablesField.Resolve()
would incorrectly assume the field had a serviceRequiredField<>
arg of the list typePublished by lukemurray about 2 years ago
Task<T>
use T
as the return typeMutationArgumentsAttribute
in mutation methods autoAddInputTypes
was being ignoredHasType()
was not checking type mappingsPublished by lukemurray about 2 years ago
Fixes
Enum
& Input
typesScalar
typeSchemaType<T>
instance. Meaning you can fetch them using schema.Type<MyEnum>()
SchemaBuilderOptions.IgnoreTypes
. Note it compares names against the Type.FullName
char
. By default this is added as a schema scalar type named Char
so the client can decide how to handle it. Over the wire it will serialize as a string (default for System.Text.Json
). You can change default scalars and mappings by using the PreBuildSchemaFromContext
action when adding your schemaservices.AddGraphQLSchema<TContext>(options => {
options.PreBuildSchemaFromContext = schema =>
{
// remove and/or add scalar types or mappings here. e.g.
schema.AddScalarType<KeyValuePair<string, string>>("StringKeyValuePair", "Represents a pair of strings");
};
})
ById
to the field name. E.g. a property List<LinePath> Line { get; set; }
previously would try to add the line: [LinePath]
field with no arguments and another field named line(id: ID!): LinePath
. This causes an error. EntityGraphQL will name add lineById(id: ID!): LinePath
. This is because the singularized version of "line" is "line".Type
instead of name allowing you to add them with your own descriptions etc.