如何设置Entity Framework Core迁移超时?

问题描述 投票:0回答:8

我正在使用最新 (1.0.0) 版本的 EF Core。我有一个迁移要在一个相当大的数据库上运行。

我跑步:

dotnet ef 数据库更新 -c ApplicationDbContext

并得到:

超时已过。超时时间在完成之前已过 操作或服务器没有响应。

在连接字符串中,我明确设置了超时,如下所示:

连接超时=150000

不幸的是,这没有帮助。我该怎么做?

c# entity-framework entity-framework-core
8个回答
81
投票

您收到的错误消息是针对 Command 超时,而不是连接超时。

更新

正如评论中 Pace 所提到的,自 EF Core 2.0 起,您可以使用

IDesignTimeDbContextFactory
在设计时通过工具创建上下文时更改上下文的行为,例如迁移时发生的情况。

在项目中创建一个实现

IDesignTimeDbContextFactory
接口的单独类,并使用
DbContextoptionsBuilder
配置您想要的行为 - 在本例中,将命令超时值设置为 600 秒:

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;

namespace EFCoreSample.Model
{
    public class SampleContextFactory : IDesignTimeDbContextFactory<SampleContext>
    {
        public SampleContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<SampleContext>();
            optionsBuilder.UseSqlServer(@"Server=.\;Database=db;Trusted_Connection=True;",
                opts => opts.CommandTimeout((int)TimeSpan.FromMinutes(10).TotalSeconds));

            return new SampleContext(optionsBuilder.Options);
        }
    }
}

确保现有的

DbContext
有一个以
DbContextOptions
对象作为参数的构造函数:

public AdventureContext(DbContextOptions options) : base(options){}

当工具运行迁移时,它首先查找实现

IDesignTimeDbContextFactory
的类,如果找到,将使用它来配置上下文。运行时行为不受影响。

原答案不再适用

使用 EF 命令时无法在上下文中设置

CommandTimeout
。但你可以在构造函数中全局设置它,如果不需要保留的话稍后再将其删除:

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext()
    {
        Database.SetCommandTimeout(150000);
    }
}

40
投票

您只需在调用 Migrations 方法之前在上下文上设置超时即可设置迁移超时:

using (var context = new DispatchingDbContext(_configuration))
{
    context.Database.SetCommandTimeout(300);
    await context.Database.MigrateAsync().ConfigureAwait(false);
}

设置迁移超时 ef .netcore


10
投票

您也可以在数据库上下文类的构造函数中执行此操作。

public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
    : base(options)
{
    Database.SetCommandTimeout(150000);
}

1
投票

您可以生成迁移 SQL 脚本并使用以下命令直接在 SQL Server 上自行运行:

dotnet ef migrations script [Baseline migration]

这样您就不会受到超时限制。

更多信息可以在这里找到。

要为 Entity Framework 6 生成此脚本,请使用:

Update-Database -Script -SourceMigration: [Baseline migration]

0
投票

使用 Entity Framework 6(非核心!),我使用

DbMigrationsConfiguration.CommandTimeout
属性为迁移设置了更长的超时。

像这样:

在我的 Global.asax.cs 中:

protected void Application_Start()
{
    DatabaseMigrationConfig.Register();
    //etc
}

我的

DatabaseMigrationConfig
班级:

public class DatabaseMigrationConfig
{
    internal static void Register()
    {
        using (var context = new MyContext(Config.ConnectionStringMigrations))
        {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext,
                                        Migrations.Configuration>());
            context.Database.Initialize(false);
        }
    }
}

我的

Migrations.Configuration
班级:

using System.Data.Entity.Migrations;

internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
        AutomaticMigrationDataLossAllowed = false;
        CommandTimeout = 360;// <----- 6 minute timeout!
    }
}

参考资料:

迁移:更新数据库命令中出现超时错误 DbMigrationsConfiguration.CommandTimeout 属性

请注意,我在迁移期间还使用了不同的连接字符串 - 用户具有比网站更高的权限,并且连接超时时间更长。请参阅此问题 - 如何使用不同的连接字符串(但相同的数据库)进行迁移


0
投票

我通过从应用程序设置文件中读取连接字符串来改进Mike Brind的答案

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;

namespace EFCoreSample.Model
{
    public class SampleContextFactory : IDesignTimeDbContextFactory<SampleContext>
    {
        public SampleContext CreateDbContext(string[] args)
        {
            var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");
            var settingsFileName = $"appsettings.{env}.json";
            
            if (!File.Exists(settingsFileName))
            {
                settingsFileName = "appsettings.json";
            }
            
            var connectionString = new ConfigurationBuilder().AddJsonFile(settingsFileName).Build().GetConnectionString("GlobalConnection");

            var optionsBuilder = new DbContextOptionsBuilder<SampleContext>();
            optionsBuilder.UseSqlServer(connectionString,
                opts => opts.CommandTimeout((int)TimeSpan.FromMinutes(10).TotalSeconds));

            return new SampleContext(optionsBuilder.Options);
        }
    }
}

0
投票

Patrick Koorevaar 的答案进行小修改,以考虑分层的 appsettings.json 文件...

public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
    public MyDbContext CreateDbContext(string[] args)
    {
        var builder = new ConfigurationBuilder();
        
        var settingsFileName = "appsettings.json";
        if (File.Exists(settingsFileName))
        {
            builder.AddJsonFile(settingsFileName);
        }
        
        var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");
        var envSettingsFileName = $"appsettings.{env}.json";
        if (File.Exists(envSettingsFileName))
        {
            builder.AddJsonFile(envSettingsFileName);
        }
        
        var connectionString = builder.Build().GetConnectionString("MyConnString");

        var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
        optionsBuilder.UseSqlServer(connectionString,
            opts => opts.CommandTimeout((int)TimeSpan.FromMinutes(10).TotalSeconds));

        return new MyDbContext(optionsBuilder.Options);
    }
}

0
投票

从 EF Core 7 开始,您现在不需要使用 DesignTimeFactory 来确定是否正在运行迁移与应用程序。由于所有配置设置,DesignTimeFactory 很痛苦。

现在您可以根据您的情况执行以下操作:

public class MyDbContext : DbContext
{
    private readonly IConfiguration _config;

    public MyDbContext(DbContextOptions options, IConfiguration config) : base(options)
    {
        _config = config;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (EF.IsDesignTime)
        {
            optionsBuilder.UseSqlServer(_config.GetConnectionString("DefaultConnection"), opt => opt.CommandTimeout(600));
        }
        base.OnConfiguring(optionsBuilder);
    }
© www.soinside.com 2019 - 2024. All rights reserved.