# Entity Framework Core - Hot Chocolate

> Learn how to integrate Entity Framework Core with Hot Chocolate, including DbContext injection and factory patterns.

Canonical source: https://chillicream.com/docs/hotchocolate/fetching-data/integrations/entity-framework

[Entity Framework Core](https://docs.microsoft.com/ef/core/) is a powerful object-relational mapping framework that has become a staple when working with SQL-based databases in .NET applications.

## Resolver Injection of a DbContext

When using the [default scope](https://chillicream.com/docs/hotchocolate/resolvers/dependency-injection#default-scope) for queries, each resolver that accepts a scoped `DbContext` receives a **separate** instance. This avoids [threading issues](https://learn.microsoft.com/en-gb/ef/core/dbcontext-configuration/#avoiding-dbcontext-threading-issues).

C#

```
public static async Task<Book?> GetBookByIdAsync(
    ApplicationDbContext dbContext) => // ...
```

When using the [default scope](https://chillicream.com/docs/hotchocolate/resolvers/dependency-injection#default-scope) for mutations, each mutation resolver that accepts a scoped `DbContext` receives the **same** request-scoped instance, as mutations execute sequentially.

C#

```
public static async Task<Book> AddBookAsync(
    AddBookInput input,
    AppDbContext dbContext) => // ...
```

See the [Dependency Injection](https://chillicream.com/docs/hotchocolate/resolvers/dependency-injection) documentation for more details.

Warning

Changing the default scope for queries will likely result in the error "A second operation started on this context before a previous operation completed", because Entity Framework Core does not support multiple parallel operations on the same `DbContext` instance.

## Using a DbContext Factory

To use a `DbContext` factory, register your `DbContext` with Hot Chocolate. Install the additional package:

Bash

```
dotnet add package HotChocolate.Data.EntityFramework
```

Warning

All `HotChocolate.*` packages need to have the same version.

Call the `RegisterDbContextFactory<T>` method on the `IRequestExecutorBuilder`. The Hot Chocolate resolver compiler then takes care of injecting your `DbContext` instance into resolvers.

C#

```
var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddDbContextFactory<ApplicationDbContext>(
        options => options.UseSqlServer("YOUR_CONNECTION_STRING"));

// ... or AddPooledDbContextFactory.

builder
    .AddGraphQL()
    .RegisterDbContextFactory<ApplicationDbContext>()
    .AddTypes();
```

C#

```
[QueryType]
public static class Query
{
    public static async Task<Book?> GetBookByIdAsync(
        Guid id,
        ApplicationDbContext dbContext)
    {
        return await dbContext.Books.FindAsync(id);
    }
}
```

Warning

You still need to add your `DbContextFactory` to the dependency injection container by calling `AddDbContextFactory<T>` or `AddPooledDbContextFactory<T>`. `RegisterDbContextFactory<T>` on its own is not enough.

## Working with a DbContext Factory

When you use a `DbContext` factory, you need to access the `DbContext` differently outside of direct resolver injection.

### DataLoaders

When creating DataLoaders that need access to your `DbContext`, inject the `IDbContextFactory<T>` through the constructor. Create and dispose the `DbContext` within the `LoadBatchAsync` method.

C#

```
public sealed class BookByIdDataLoader : BatchDataLoader<Guid, Book>
{
    private readonly IDbContextFactory<AppDbContext>
        _dbContextFactory;

    public BookByIdDataLoader(
        IDbContextFactory<AppDbContext> dbContextFactory,
        IBatchScheduler batchScheduler,
        DataLoaderOptions options)
        : base(batchScheduler, options)
    {
        _dbContextFactory = dbContextFactory;
    }

    protected override async Task<IReadOnlyDictionary<Guid, Book>>
        LoadBatchAsync(
            IReadOnlyList<Guid> keys,
            CancellationToken cancellationToken)
    {
        using AppDbContext dbContext =
            _dbContextFactory.CreateDbContext();

        return await dbContext.Books
            .Where(b => keys.Contains(b.Id))
            .ToDictionaryAsync(b => b.Id, cancellationToken);
    }
}
```

Warning

Dispose the `DbContext` after use. The example above uses the `using` statement for this purpose.

### Services

Services that need a `DbContext` should inject `IDbContextFactory<T>` instead of the `DbContext` directly.

C#

```
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContextFactory<ApplicationDbContext>(
    options => options.UseSqlServer("YOUR_CONNECTION_STRING"));

builder.Services.AddScoped<BookService>();

builder
    .AddGraphQL()
    .AddTypes();
```

C#

```
public sealed class BookService : IAsyncDisposable
{
    private readonly ApplicationDbContext _dbContext;

    public BookService(
        IDbContextFactory<ApplicationDbContext> dbContextFactory)
    {
        _dbContext = dbContextFactory.CreateDbContext();
    }

    public async Task<Book?> GetBookAsync(Guid id)
    {
        return await _dbContext.Books.FindAsync(id);
    }

    public ValueTask DisposeAsync()
    {
        return _dbContext.DisposeAsync();
    }
}
```

C#

```
[QueryType]
public static class Query
{
    public static async Task<Book?> GetBookByIdAsync(
        Guid id,
        BookService bookService)
    {
        return await bookService.GetBookAsync(id);
    }
}
```

Warning

Dispose the `DbContext` when the service is disposed. The example above implements `IAsyncDisposable` and disposes the `DbContext` in `DisposeAsync`.

## Next Steps

- [Dependency Injection](https://chillicream.com/docs/hotchocolate/resolvers/dependency-injection) for DI scope configuration
- [DataLoader](https://chillicream.com/docs/hotchocolate/fetching-data/batching/dataloader) for batching patterns
- [Filtering](https://chillicream.com/docs/hotchocolate/fetching-data/filtering) for applying filters to EF Core queries
[Edit this page on GitHub](https://github.com/ChilliCream/graphql-platform/edit/main/website/content/docs/hotchocolate/fetching-data/integrations/entity-framework.md)

Last updated on **June 30, 2026** by **Tobias Tengler**
