-
Notifications
You must be signed in to change notification settings - Fork 63
Introduces projection-based field resolution to ensure safe access to navigation properties and enforced through compile-time analysis. #1212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
…phQL.EntityFramework into projection-part-2
Foreign keys were not being included when building projections for nested navigations (e.g., members in a politicalParty query). This caused FK properties like PoliticalPartyId to be Guid.Empty, leading to 'Sequence contains no elements' errors when custom field resolvers tried to use them. The fix adds a new section in TryBuildNavigationBindings that explicitly binds foreign key properties, similar to how it's done in BuildExpression for top-level entities.
Tests verify that foreign keys are properly included when querying nested navigation properties. This ensures custom field resolvers that depend on foreign keys work correctly. The tests cover: - Custom fields that use foreign keys to query related data - Foreign key values being non-empty (not Guid.Empty) in nested projections - Integration with the projection system These tests demonstrate the bug that was fixed in commit 031931b where foreign keys were missing from nested navigation projections.
This reverts commit cf07833.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Introduces projection-based field resolution to ensure safe access to navigation properties and enforced through compile-time analysis.
What's New
Roslyn Analyzer for Compile-Time Safety
A new analyzer package (
GraphQL.EntityFramework.Analyzers) detects problematic usage patterns at build time:GQLEF002 Warning
Detects unsafe access to navigation properties in
Field().Resolve()/Field().ResolveAsync()calls.What's Safe:
context.Source.Id)context.Source.ParentId)What's Unsafe:
context.Source.Parent)context.Source.Name,context.Source.Age)context.Source.Parent.Id)The analyzer will suggest using projection-based extension methods for unsafe patterns.
GQLEF003 Error
Prevents identity projection (
_ => _) in projection-based methods. Identity projection defeats the purpose of the projection system and doesn't load any additional navigation properties.What to do instead:
Resolve()for PK/FK accessx => x.Parent)Projection-Based FieldBuilder Extensions
New extension methods on
FieldBuilderfor safe custom resolvers:Synchronous Resolution
snippet source | anchor
Asynchronous Resolution
snippet source | anchor
List Resolution
snippet source | anchor
These methods provide
ResolveProjectionContext<TDbContext, TProjection>with access to:Projection- The projected dataDbContext- The current DbContextUser- The current user (ClaimsPrincipal)Filters- Global filtersFieldContext- The GraphQL field contextProjection-Based Navigation Field Methods
New overloads for navigation fields with built-in projection support.
Single Navigation
Simple - Direct Projection:
snippet source | anchor
Complex - With Custom Resolver:
snippet source | anchor
List Navigation
Simple - Direct Projection:
snippet source | anchor
Complex - With Custom Resolver:
snippet source | anchor
Connection Navigation (Pagination)
Simple - Direct Projection:
snippet source | anchor
Complex - With Custom Resolver:
snippet source | anchor
All new navigation methods properly apply filters and support GraphQL query arguments (where, orderBy, skip, take, ids).
AutoMap Filter Support
AutoMap()now properly applies filters to auto-mapped navigation fields:AddNavigationFieldandAddNavigationListFieldMigration Guide
Step 1: Update Navigation Fields
Old Style (Deprecated):
snippet source | anchor
New Style (Projection-based):
snippet source | anchor
Step 2: Update Custom Resolvers
Old Style (Unsafe):
snippet source | anchor
New Style (Safe with Projection):
snippet source | anchor
Step 3: Keep Safe PK/FK Access Direct
Primary key and foreign key access doesn't require projection:
snippet source | anchor
Breaking Changes
Deprecated Methods
The following methods are now marked
[Obsolete]and will generate compiler warnings:AddNavigationField<TSource, TReturn>(..., Func<ResolveEfFieldContext, TReturn> resolve, ...)AddNavigationListField<TSource, TReturn>(..., Func<ResolveEfFieldContext, IEnumerable<TReturn>> resolve, ...)AddNavigationConnectionField<TSource, TReturn>(..., Func<ResolveEfFieldContext, IEnumerable<TReturn>> resolve, ...)These methods will be removed in a future major version. Migrate to projection-based overloads.
Benefits
Compile-Time Safety
The Roslyn analyzer catches navigation property access issues at build time, preventing runtime null reference exceptions.
Better Performance
Explicit projections allow EF Core to generate more efficient SQL queries by only loading required data.
Clearer Intent
Projection expressions clearly document which navigation properties are required for each resolver.
Automatic Filter Application
Projection-based methods automatically apply global and entity-specific filters, ensuring consistent authorization.
Troubleshooting
"IEfGraphQLService not found in request services"
Ensure the DbContext is registered with
EfGraphQLConventions.RegisterInContainer<TDbContext>()."Navigation property is null in resolver"
This occurs when accessing a navigation property without projection. Use the projection-based extension methods or navigation field overloads.
"GQLEF002 warning on valid code"
When only accessing primary keys or foreign keys, the warning is a false positive. The analyzer uses heuristics and may occasionally flag safe code. Options include:
#pragma warning disable GQLEF002for specific linesctx.Source.ParentIdinstead ofctx.Source.Parent.Id)"GQLEF003 error on identity projection"
Don't use
_ => _in projection-based methods. Options:Resolve()when only needing PK/FKx => x.ParentAdditional Resources