[C#] How to Set Command Timeout in Entity Framework Core

目次

Overview

This article explains how to set the waiting time (timeout) for Entity Framework Core (EF Core) when executing SQL against a database. By extending the timeout value, you can prevent intentional disconnections (TimeoutException) during long-running aggregation tasks or bulk update processes that exceed the default limit (usually 30 seconds).

Specifications (Input/Output)

  • Input: Timeout duration in seconds (int).
  • Output: A DbContext instance with the configuration applied.
  • Prerequisites: .NET 6.0 or higher. Works with relational database providers such as SQLite, SQL Server, and PostgreSQL. This example uses Microsoft.EntityFrameworkCore.Sqlite.

Basic Usage

You can configure the timeout using an action delegate in the second argument of the provider configuration methods (e.g., UseSqlite, UseSqlServer) within the DbContextOptionsBuilder.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlite("Data Source=app.db", options =>
    {
        // Set timeout to 180 seconds (3 minutes)
        options.CommandTimeout(180);
    });
}

Full Code Example

The following is a complete example of configuring the timeout value when initializing a DbContext in a console application. If you are using a DI container (AddDbContext), the notation is the same, though the configuration will be located in Program.cs.

The Microsoft.EntityFrameworkCore.Sqlite package is required. dotnet add package Microsoft.EntityFrameworkCore.Sqlite

using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

public class Program
{
    public static async Task Main()
    {
        // Use the Context with the timeout setting applied
        using (var context = new LongRunningContext())
        {
            // Create the database
            await context.Database.EnsureDeletedAsync();
            await context.Database.EnsureCreatedAsync();

            Console.WriteLine($"Current Timeout: {context.Database.GetCommandTimeout()} seconds");

            // Execute standard data operations
            context.Products.Add(new Product { Name = "Heavy Calculation Item" });
            await context.SaveChangesAsync();
            
            Console.WriteLine("Database operation completed.");
        }
    }
}

// DbContext definition
public class LongRunningContext : DbContext
{
    public LongRunningContext() { }
    public LongRunningContext(DbContextOptions<LongRunningContext> options) : base(options) { }

    public DbSet<Product> Products => Set<Product>();

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        // Only configure if not already configured (to prioritize DI container settings)
        if (!optionsBuilder.IsConfigured)
        {
            var connectionString = "Data Source=app.db";

            optionsBuilder.UseSqlite(connectionString, sqliteOptions =>
            {
                // Key Point:
                // Set the command execution timeout to 180 seconds (3 minutes)
                // The default is typically 30 seconds
                sqliteOptions.CommandTimeout(180);
            });
            
            // Log output for verification
            optionsBuilder.LogTo(Console.WriteLine, Microsoft.Extensions.Logging.LogLevel.Information);
        }
    }
}

// Entity definition
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
}

Customization Points

  • DI Container Configuration (ASP.NET Core, etc.): When using AddDbContext in Program.cs, write it as follows:C#builder.Services.AddDbContext<LongRunningContext>(options => options.UseSqlite(connectionString, providerOptions => providerOptions.CommandTimeout(180) ) );
  • Temporary Changes: If you want to extend the timeout only for a specific heavy task rather than the entire application, you can change it dynamically in the code (see Advanced Application).

Important Notes

  • Default Values: Most providers default to 30 seconds. If not set, queries taking longer than 30 seconds will fail with OperationCanceledException or SqlException.
  • Overly Long Settings: Setting an unnecessarily long time (or 0 for infinite) can prevent database locks from being released, potentially blocking access for other users. Apply this only where necessary.
  • Difference from Connection Timeout: CommandTimeout is the “wait time for a query to execute.” This is different from the “wait time to connect to the DB,” which is defined in the connection string as Connect Timeout. Do not confuse the two.

Advanced Application

Changing the Timeout for a Specific Process

This method allows you to extend the time only for a specific heavy report generation process without changing the settings for the entire Context.

using (var context = new LongRunningContext())
{
    // Temporarily change the timeout for this context instance to 5 minutes
    context.Database.SetCommandTimeout(300);

    // Execute a time-consuming aggregation process
    // await context.Database.ExecuteSqlRawAsync("EXEC VeryHeavyStoredProcedure");
    
    // You can revert it to the default afterward (or simply dispose of the Context)
    context.Database.SetCommandTimeout(null); // Setting to null reverts to default
}

Conclusion

Use OnConfiguring or AddDbContext for global settings, and Database.SetCommandTimeout for local adjustments.

This setting is effective for batch processing or large data migrations where you know a process will take time.

Specify the CommandTimeout within the options lambda expression of UseSqlite or UseSqlServer.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次