Title:
Bug: Regression in v6.1.5 - Expression.Call fails with Type Mismatch (Select not found) on any single object Resolve or ResolveBulk configuration
Description
Note: This critical regression specifically started appearing in version v6.1.5.
The issue occurs when configuring any field that resolves to a Single Object (not a collection) using either .Resolve() or .ResolveBulk() / .ResolveBulkAsync(). It is not caused by mixing the two configurations together, but rather a fundamental type resolution defect within EntityGraphQL's expression compiler for this version.
During the execution plan phase, the library attempts to inject an Enumerable.Select call to project the node data. However, since the field returns a single object reference, the compiler passes a non-enumerable type into the first parameter of Select. This causes the internal reflection binding to fail and throws an InvalidOperationException: "Could not find extension method Select on types System.Linq.Enumerable".
GraphQL Query Triggering the Bug
The runtime exception is thrown when executing a query that requests a single-object nested field (the error crashes exactly at the invoiceDetail node):
query GetSalesData {
salesSystem {
orders(take: 10, sort: [{ createdAt: DESC }]) {
id
amount
description
userCreatedId
userUpdatedId
userId
resourceType
type
status
createdAt
updatedAt
invoiceDetail { # <--- CRASHES HERE (Single Object Node)
id
orderId
userCreatedId
payoutAmount
pointsUsed
conversionRate
paymentMethod
accountNumber
createdAt
updatedAt
}
}
ordersCount
}
}
Steps to Reproduce / Code Snippet
The compiler crashes during query execution when the nested single-object field is mapped in the schema (the bug replicates regardless of using standard resolve or bulk loader extensions independently):
// Inside your SchemaBuilder / Map fields setup
schema.SchemaType<Order>()
.AddField("invoiceDetail", null)
// The bug triggers because "invoiceDetail" returns a single object context,
// but the engine attempts an Enumerable.Select operation on it behind the scenes
.Resolve<CompanyContext>((p, ctx) =>
ctx.SalesSystem.Invoices.ToModelClean().FirstOrDefault(y => y.Id == p.Id)
);
Expected Behavior
The schema query engine should detect that the field node evaluates to a single object type and skip injecting collection-oriented methods like Select. If a translation layer is needed for execution mappings, it should bind correctly to the object's instance properties or delegate calls instead of treating it as an IEnumerable.
Actual Behavior & Stack Trace
The execution crashes with the following exception stack trace:
EntityGraphQLException: Could not find extension method Select on types System.Linq.Enumerable
---> System.InvalidOperationException: No generic method 'Select' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments.
at System.Linq.Expressions.Expression.Call(Type type, String methodName, Type[] typeArguments, Expression[] arguments)
Debug Inspection Insights:
Inside the internal MakeCallOnEnumerable helper method, we can observe that:
genericTypes correctly includes the target single object type (InvoiceSummary).
- The first element of
parameters (representing baseExp) has a concrete Type of InvoiceSummary (the single object) instead of an IEnumerable<InvoiceSummary>. This type mismatch causes the .NET Expression Tree builder to reject the signature match.
Workaround
Currently, the issue can be temporarily bypassed by forcing the entire endpoint execution chain into an explicit asynchronous pipeline (ResolveAsync), which formats the compilation sequence differently and avoids the broken translation branch.
Environment
- EntityGraphQL Version: v6.1.5 (Regression confirmed in this version)
- .NET Runtime: .NET 8.0
Title:
Bug: Regression in v6.1.5 -
Expression.Callfails with Type Mismatch (Selectnot found) on any single objectResolveorResolveBulkconfigurationDescription
Note: This critical regression specifically started appearing in version v6.1.5.
The issue occurs when configuring any field that resolves to a Single Object (not a collection) using either
.Resolve()or.ResolveBulk() / .ResolveBulkAsync(). It is not caused by mixing the two configurations together, but rather a fundamental type resolution defect within EntityGraphQL's expression compiler for this version.During the execution plan phase, the library attempts to inject an
Enumerable.Selectcall to project the node data. However, since the field returns a single object reference, the compiler passes a non-enumerable type into the first parameter ofSelect. This causes the internal reflection binding to fail and throws anInvalidOperationException: "Could not find extension method Select on types System.Linq.Enumerable".GraphQL Query Triggering the Bug
The runtime exception is thrown when executing a query that requests a single-object nested field (the error crashes exactly at the
invoiceDetailnode):Steps to Reproduce / Code Snippet
The compiler crashes during query execution when the nested single-object field is mapped in the schema (the bug replicates regardless of using standard resolve or bulk loader extensions independently):
Expected Behavior
The schema query engine should detect that the field node evaluates to a single object type and skip injecting collection-oriented methods like
Select. If a translation layer is needed for execution mappings, it should bind correctly to the object's instance properties or delegate calls instead of treating it as anIEnumerable.Actual Behavior & Stack Trace
The execution crashes with the following exception stack trace:
Debug Inspection Insights:
Inside the internal
MakeCallOnEnumerablehelper method, we can observe that:genericTypescorrectly includes the target single object type (InvoiceSummary).parameters(representingbaseExp) has a concreteTypeofInvoiceSummary(the single object) instead of anIEnumerable<InvoiceSummary>. This type mismatch causes the.NET Expression Treebuilder to reject the signature match.Workaround
Currently, the issue can be temporarily bypassed by forcing the entire endpoint execution chain into an explicit asynchronous pipeline (
ResolveAsync), which formats the compilation sequence differently and avoids the broken translation branch.Environment