# Configuration

## The `DbContext` lifetime <a href="#the-dbcontext-lifetime" id="the-dbcontext-lifetime"></a>

The lifetime of a `DbContext` begins when the instance is created and ends when the instance is disposed.

A `DbContext` instance is designed to be used for a *single* unit-of-work. This means that the lifetime of a `DbContext` instance is usually very short.

> "A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work." - [Martin Fowler](https://martinfowler.com/)

A typical unit-of-work when using Entity Framework Core (EF Core) involves:

1. Creation of a `DbContext` instance
2. Tracking of entity instances by the context. Entities become tracked by
   1. Being returned from a query
   2. Being added or attached to the context
3. Changes are made to the tracked entities as needed to implement the business rule
4. SaveChanges or SaveChangesAsync is called. EF Core detects the changes made and writes them to the database.
5. The `DbContext` instance is disposed

{% hint style="info" %}

* It is very important to dispose the DbContext after use. This ensures any:
  * unmanaged resources are freed,&#x20;
  * events or other hooks are unregistered so as to prevent memory leaks in case the instance remains referenced.
* DbContext is **not thread-safe**. Do not share contexts between threads. Make sure to await all async calls before continuing to use the context instance.
* An `InvalidOperationException` thrown by EF Core code can put the context into an unrecoverable state. Such exceptions indicate a program error and are not designed to be recovered from.
  {% endhint %}

### DbContextOptions <a href="#dbcontextoptions" id="dbcontextoptions"></a>

The starting point for all `DbContext` configuration is `DbContextOptionsBuilder`.\
There are three ways to get this builder:

* In `AddDbContext` and related methods
* In `OnConfiguring`
* Constructed explicitly with `new`

{% tabs %}
{% tab title="Using ConnectionString" %}

```csharp
public class ApplicationContext : DbContext
{
    private readonly string _connectionString;
    
    public ApplicationContext(string connectionString)
    {
        _connectionString = connectionString;
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        // SQL Server or Azure SQL
        optionsBuilder.UseSqlServer(_connectionString);
        // Azure Cosmos DB
        // optionsBuilder.UseCosmos(_connectionString, databaseName);
        // SQLite
        // optionsBuilder.UseSqlite(_connectionString);
        // EF Core in-memory database
        // optionsBuilder.UseInMemoryDatabase(_databaseName);
        // PostgreSQL
        // optionsBuilder.UseNpgsql(_connectionString);
        // MySQL/MariaDB*
        // optionsBuilder.UseMySql(_connectionString);
        // Oracle
        // optionsBuilder.UseOracle(_connectionString);
    }
}
```

{% endtab %}

{% tab title="Using DbContextOptions" %}

<pre class="language-csharp"><code class="lang-csharp"><strong>public class ApplicationContext : DbContext
</strong>{
    public ApplicationDbContext(DbContextOptions&#x3C;ApplicationDbContext> options)
        : base(options)
    {
    }
}
</code></pre>

```csharp
var contextOptions = new DbContextOptionsBuilder<ApplicationDbContext>()
    .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0")
    .Options;

using var context = new ApplicationDbContext(contextOptions);
```

{% endtab %}

{% tab title="Using DbContextFactory" %}

```csharp
public class ApplicationContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationContext> options)
        : base(options)
    {
    }
}
```

{% code title="Program.cs" %}

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContextFactory<ApplicationContext>(
        options => options.UseSqlServer(
            @"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0"));
}
```

{% endcode %}

```csharp
private readonly IDbContextFactory<ApplicationDbContext> _contextFactory;

public MyController(IDbContextFactory<ApplicationContext> contextFactory)
{
    _contextFactory = contextFactory;
}

public async Task DoSomething()
{
    using (var context = _contextFactory.CreateDbContext())
    {
        // ...
    }
}
```

{% endtab %}
{% endtabs %}

#### `DbContextOptions` versus `DbContextOptions<TContext>` <a href="#dbcontextoptions-versus-dbcontextoptionstcontext" id="dbcontextoptions-versus-dbcontextoptionstcontext"></a>

Most `DbContext` subclasses that accept a `DbContextOptions` should use the generic `DbContextOptions<TContext>` variation.

This ensures that the correct options for the specific `DbContext` subtype are resolved from dependency injection, even when multiple `DbContext` subtypes are registered.

{% hint style="info" icon="lightbulb-exclamation-on" %}
Your `DbContext` does not need to be sealed, but sealing is best practice to do so for classes not designed to be inherited from.
{% endhint %}

### Avoiding DbContext threading issues <a href="#avoiding-dbcontext-threading-issues" id="avoiding-dbcontext-threading-issues"></a>

Entity Framework Core does not support multiple parallel operations being run on the same `DbContext` instance. This includes both parallel execution of async queries and any explicit concurrent use from multiple threads. Therefore, always `await` async calls immediately, or use separate `DbContext` instances for operations that execute in parallel.

When EF Core detects an attempt to use a `DbContext` instance concurrently, the application will throw an `InvalidOperationException`.

Always `await` EF Core asynchronous methods immediately.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://dailyjournal.gitbook.io/notes/orms/entity-framework/configuration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
