Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 9 additions & 42 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ A delegate that resolves the DbContext.
```cs
namespace GraphQL.EntityFramework;

public delegate TDbContext ResolveDbContext<out TDbContext>(object userContext)
public delegate TDbContext ResolveDbContext<out TDbContext>(object userContext, IServiceProvider? requestServices)
where TDbContext : DbContext;
```
<sup><a href='/src/GraphQL.EntityFramework/GraphApi/ResolveDbContext.cs#L1-L4' title='Snippet source file'>snippet source</a> | <a href='#snippet-ResolveDbContext.cs' title='Start of snippet'>anchor</a></sup>
Expand Down Expand Up @@ -298,23 +298,6 @@ public class GraphQlController(ISchema schema, IDocumentExecuter executer) :
Multiple different DbContext types can be registered and used.


### UserContext

A user context that exposes both types.

<!-- snippet: MultiUserContext -->
<a id='snippet-MultiUserContext'></a>
```cs
public class UserContext(DbContext1 context1, DbContext2 context2) : Dictionary<string, object?>
{
public readonly DbContext1 DbContext1 = context1;
public readonly DbContext2 DbContext2 = context2;
}
```
<sup><a href='/src/Tests/MultiContextTests/MultiContextTests.cs#L80-L86' title='Snippet source file'>snippet source</a> | <a href='#snippet-MultiUserContext' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


### Register in container

Register both DbContext types in the container and include how those instance can be extracted from the GraphQL context:
Expand All @@ -324,10 +307,10 @@ Register both DbContext types in the container and include how those instance ca
```cs
EfGraphQLConventions.RegisterInContainer(
services,
userContext => ((UserContext) userContext).DbContext1);
(_, requestServices) => requestServices!.GetRequiredService<DbContext1>());
EfGraphQLConventions.RegisterInContainer(
services,
userContext => ((UserContext) userContext).DbContext2);
(_, requestServices) => requestServices!.GetRequiredService<DbContext2>());
```
<sup><a href='/src/Tests/MultiContextTests/MultiContextTests.cs#L49-L58' title='Snippet source file'>snippet source</a> | <a href='#snippet-RegisterMultipleInContainer' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->
Expand All @@ -345,7 +328,7 @@ var executionOptions = new ExecutionOptions
{
Schema = schema,
Query = query,
UserContext = new UserContext(dbContext1, dbContext2)
RequestServices = provider,
};
```
<sup><a href='/src/Tests/MultiContextTests/MultiContextTests.cs#L64-L73' title='Snippet source file'>snippet source</a> | <a href='#snippet-MultiExecutionOptions' title='Start of snippet'>anchor</a></sup>
Expand All @@ -369,39 +352,23 @@ public class MultiContextQuery :
efGraphQlService1.AddSingleField(
graph: this,
name: "entity1",
resolve: context =>
{
var userContext = (UserContext) context.UserContext;
return userContext.DbContext1.Entities;
});
resolve: _ => _.DbContext.Entities);
efGraphQlService1.AddFirstField(
graph: this,
name: "entity1First",
resolve: context =>
{
var userContext = (UserContext) context.UserContext;
return userContext.DbContext1.Entities;
});
resolve: _ => _.DbContext.Entities);
efGraphQlService2.AddSingleField(
graph: this,
name: "entity2",
resolve: context =>
{
var userContext = (UserContext) context.UserContext;
return userContext.DbContext2.Entities;
});
resolve: _ => _.DbContext.Entities);
efGraphQlService2.AddFirstField(
graph: this,
name: "entity2First",
resolve: context =>
{
var userContext = (UserContext) context.UserContext;
return userContext.DbContext2.Entities;
});
resolve: _ => _.DbContext.Entities);
}
}
```
<sup><a href='/src/Tests/MultiContextTests/MultiContextQuery.cs#L1-L41' title='Snippet source file'>snippet source</a> | <a href='#snippet-MultiContextQuery.cs' title='Start of snippet'>anchor</a></sup>
<sup><a href='/src/Tests/MultiContextTests/MultiContextQuery.cs#L1-L25' title='Snippet source file'>snippet source</a> | <a href='#snippet-MultiContextQuery.cs' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->


Expand Down
7 changes: 0 additions & 7 deletions docs/mdsource/configuration.source.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,6 @@ snippet: GraphQlController
Multiple different DbContext types can be registered and used.


### UserContext

A user context that exposes both types.

snippet: MultiUserContext


### Register in container

Register both DbContext types in the container and include how those instance can be extracted from the GraphQL context:
Expand Down
17 changes: 11 additions & 6 deletions src/GraphQL.EntityFramework/EfGraphQLConventions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,8 @@ public static void RegisterInContainer<TDbContext>(
RegisterScalarsAndArgs(services);
services.AddHttpContextAccessor();
services.AddTransient<HttpContextCapture>();
services.AddSingleton(
provider => Build(resolveDbContext, model, resolveFilters, provider, disableTracking, disableAsync));
services.AddSingleton<IEfGraphQLService<TDbContext>>(
provider => provider.GetRequiredService<EfGraphQLService<TDbContext>>());
services.AddSingleton(provider => Build(resolveDbContext, model, resolveFilters, provider, disableTracking, disableAsync));
services.AddSingleton<IEfGraphQLService<TDbContext>>(provider => provider.GetRequiredService<EfGraphQLService<TDbContext>>());
}

static EfGraphQLService<TDbContext> Build<TDbContext>(
Expand All @@ -45,7 +43,7 @@ static EfGraphQLService<TDbContext> Build<TDbContext>(
{
model ??= ResolveModel<TDbContext>(provider);
filters ??= provider.GetService<ResolveFilters<TDbContext>>();
dbContextResolver ??= _ => DbContextFromProvider<TDbContext>(provider);
dbContextResolver ??= (_, requestServices) => DbContextFromProvider<TDbContext>(provider, requestServices);

return new(
model,
Expand All @@ -55,9 +53,16 @@ static EfGraphQLService<TDbContext> Build<TDbContext>(
disableAsync);
}

static TDbContext DbContextFromProvider<TDbContext>(IServiceProvider provider)
static TDbContext DbContextFromProvider<TDbContext>(IServiceProvider provider, IServiceProvider? requestServices)
where TDbContext : DbContext
{
var dataFromRequestServices = requestServices?
.GetService<TDbContext>();
if (dataFromRequestServices is not null)
{
return dataFromRequestServices;
}

var dataFromHttpContext = provider.GetService<HttpContextCapture>()?
.HttpContextAccessor
.HttpContext?
Expand Down
9 changes: 7 additions & 2 deletions src/GraphQL.EntityFramework/GraphApi/EfGraphQLService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,13 @@ ResolveEfFieldContext<TDbContext, TSource> BuildContext<TSource>(
User = context.User
};

public TDbContext ResolveDbContext(IResolveFieldContext context) =>
resolveDbContext(context.UserContext);
public TDbContext ResolveDbContext(IResolveFieldContext fieldContext)
{
var userContext = fieldContext.UserContext;
var executionContext = fieldContext.ExecutionContext;
var requestServices = executionContext.RequestServices ?? executionContext.ExecutionOptions.RequestServices;
return resolveDbContext(userContext, requestServices);
}

Filters<TDbContext>? ResolveFilter<TSource>(IResolveFieldContext<TSource> context) =>
resolveFilters?.Invoke(context.UserContext);
Expand Down
2 changes: 1 addition & 1 deletion src/GraphQL.EntityFramework/GraphApi/ResolveDbContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace GraphQL.EntityFramework;

public delegate TDbContext ResolveDbContext<out TDbContext>(object userContext)
public delegate TDbContext ResolveDbContext<out TDbContext>(object userContext, IServiceProvider? requestServices)
where TDbContext : DbContext;
2 changes: 0 additions & 2 deletions src/SampleWeb/Subscription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@
// {
// Document = document,
// Schema = schema,
// UserContext = new UserContext(dbContext),
// Variables = variableValues,
// Fragments = document.Fragments,
// CancellationToken = token,
Expand Down Expand Up @@ -141,7 +140,6 @@
// Document = context.Document,
// Fragments = context.Fragments,
// RootValue = context.RootValue,
// UserContext = context.UserContext,
// Operation = context.Operation,
// Variables = context.Variables,
// CancellationToken = context.CancellationToken,
Expand Down
5 changes: 0 additions & 5 deletions src/SampleWeb/UserContext.cs

This file was deleted.

24 changes: 12 additions & 12 deletions src/Tests/DependencyResolutionTests/DependencyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ public async Task ExplicitModel()
services.AddSingleton<DependencySchema>();
EfGraphQLConventions.RegisterInContainer(
services,
userContext => ((UserContextSingleDb<DependencyDbContext>) userContext).DbContext,
(_, _) => dbContext,
sqlInstance.Model);
await using var provider = services.BuildServiceProvider();
using var schema = provider.GetRequiredService<DependencySchema>();
var executionOptions = new ExecutionOptions
{
Schema = schema,
Query = query,
UserContext = new UserContextSingleDb<DependencyDbContext>(dbContext),
Variables = null
Variables = null,
RequestServices = provider
};

await ExecutionResultData(executionOptions);
Expand All @@ -50,15 +50,15 @@ public async Task ScopedDbContext()

EfGraphQLConventions.RegisterInContainer(
services,
userContext => ((UserContextSingleDb<DependencyDbContext>) userContext).DbContext);
(_, requestServices) => requestServices!.GetRequiredService<DependencyDbContext>());
await using var provider = services.BuildServiceProvider();
using var schema = new DependencySchema(provider);
var executionOptions = new ExecutionOptions
{
Schema = schema,
Query = query,
UserContext = new UserContextSingleDb<DependencyDbContext>(dbContext),
Variables = null
Variables = null,
RequestServices = provider
};

await ExecutionResultData(executionOptions);
Expand All @@ -75,15 +75,15 @@ public async Task TransientDbContext()

EfGraphQLConventions.RegisterInContainer(
services,
userContext => ((UserContextSingleDb<DependencyDbContext>) userContext).DbContext);
(_, requestServices) => requestServices!.GetRequiredService<DependencyDbContext>());
await using var provider = services.BuildServiceProvider();
using var schema = new DependencySchema(provider);
var options = new ExecutionOptions
{
Schema = schema,
Query = query,
UserContext = new UserContextSingleDb<DependencyDbContext>(dbContext),
Variables = null
Variables = null,
RequestServices = provider
};

await ExecutionResultData(options);
Expand All @@ -100,15 +100,15 @@ public async Task SingletonDbContext()

EfGraphQLConventions.RegisterInContainer(
services,
userContext => ((UserContextSingleDb<DependencyDbContext>) userContext).DbContext);
(_, requestServices) => requestServices!.GetRequiredService<DependencyDbContext>());
await using var provider = services.BuildServiceProvider();
using var schema = new DependencySchema(provider);
var options = new ExecutionOptions
{
Schema = schema,
Query = query,
UserContext = new UserContextSingleDb<DependencyDbContext>(dbContext),
Variables = null
Variables = null,
RequestServices = provider
};

await ExecutionResultData(options);
Expand Down
2 changes: 1 addition & 1 deletion src/Tests/IntegrationTests/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public async Task SchemaPrint()
services.AddSingleton(type);
}

EfGraphQLConventions.RegisterInContainer(services, _ => dbContext, dbContext.Model);
EfGraphQLConventions.RegisterInContainer(services, (_, _) => dbContext, dbContext.Model);
await using var provider = services.BuildServiceProvider();
using var schema = new Schema(provider);

Expand Down
4 changes: 2 additions & 2 deletions src/Tests/IntegrationTests/QueryExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public static async Task<string> ExecuteQuery<TDbContext>(
{
EfGraphQLConventions.RegisterInContainer(
services,
_ => data,
(_, _) => data,
data.Model,
_ => filters,
disableTracking,
Expand All @@ -26,8 +26,8 @@ public static async Task<string> ExecuteQuery<TDbContext>(
Schema = schema,
Query = query,
ThrowOnUnhandledException = true,
UserContext = new UserContextSingleDb<TDbContext>(data),
Variables = inputs,
RequestServices = provider,
};

var result = await executer.ExecuteWithErrorCheck(options);
Expand Down
20 changes: 16 additions & 4 deletions src/Tests/Mapping/MappingTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
public class MappingTests
using ExecutionContext = GraphQL.Execution.ExecutionContext;

public class MappingTests
{
static SqlInstance<MappingContext> sqlInstance;

Expand Down Expand Up @@ -43,22 +45,32 @@ public async Task Resolve()
await database.AddDataUntracked(child, parent);
var services = new ServiceCollection();
services.AddSingleton<MappingQuery>();
EfGraphQLConventions.RegisterInContainer(services,_ => database.NewDbContext(), model:sqlInstance.Model);
EfGraphQLConventions.RegisterInContainer(services, (_, _) => database.NewDbContext(), model: sqlInstance.Model);
await using var provider = services.BuildServiceProvider();
var mappingQuery = provider.GetRequiredService<MappingQuery>();

var fieldContext = new ResolveFieldContext
{
ExecutionContext = new ExecutionContext
{
RequestServices = provider
}
};
var resolve = await mappingQuery.Fields
.Single(_ => _.Name == "children")
.Resolver!
.ResolveAsync(new ResolveFieldContext());
.ResolveAsync(fieldContext);
await Verify(resolve);
}

[Fact]
public async Task PropertyToObject()
{
var expression = Mapper<MappingContext>.PropertyToObject<MappingParent>("Property");
var result = expression.Compile()(new() {Property = "value"});
var result = expression.Compile()(new()
{
Property = "value"
});
await Verify(
new
{
Expand Down
24 changes: 4 additions & 20 deletions src/Tests/MultiContextTests/MultiContextQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,18 @@ public MultiContextQuery(
efGraphQlService1.AddSingleField(
graph: this,
name: "entity1",
resolve: context =>
{
var userContext = (UserContext) context.UserContext;
return userContext.DbContext1.Entities;
});
resolve: _ => _.DbContext.Entities);
efGraphQlService1.AddFirstField(
graph: this,
name: "entity1First",
resolve: context =>
{
var userContext = (UserContext) context.UserContext;
return userContext.DbContext1.Entities;
});
resolve: _ => _.DbContext.Entities);
efGraphQlService2.AddSingleField(
graph: this,
name: "entity2",
resolve: context =>
{
var userContext = (UserContext) context.UserContext;
return userContext.DbContext2.Entities;
});
resolve: _ => _.DbContext.Entities);
efGraphQlService2.AddFirstField(
graph: this,
name: "entity2First",
resolve: context =>
{
var userContext = (UserContext) context.UserContext;
return userContext.DbContext2.Entities;
});
resolve: _ => _.DbContext.Entities);
}
}
Loading