如何在ASP.NET Core / Entity Framework Core中设置命令超时时间?

103
命令超时设置的位置与早期版本不再相同。
然而,我找不到任何地方说明如何更改这个设置。
我正在上传非常大的文件,保存所需的时间超过默认的30秒。
请注意,我询问的是命令超时,而不是另一个问题中的迁移超时。

2
看一下如何设置Entity Framework Core迁移超时时间? - 使用Database.SetCommandTimeout的答案。 - Ivan Stoev
可能是如何设置Entity Framework Core迁移超时时间?的重复问题。 - Mike Brind
5个回答

197
如果您正在使用DI容器来管理DbContext(即将DbContext添加到服务集合中),则可以在选项中指定命令超时时间。
在Startup.ConfigureServices中:
services.AddDbContext<YourDbContext>(options => options.UseSqlServer(
    this.Configuration.GetConnectionString("YourConnectionString"),
    sqlServerOptions => sqlServerOptions.CommandTimeout(60))
);

6
这是最合理的方法,使用内置的配置API,配置是解耦且易于更改,是负责配置的类的一部分。所有其他选项都有点像黑客手段。 - Edgars Pivovarenoks
在.NET 6/EF6中似乎不再起作用 - 没有CommandTImeout方法,也没有SetCommandTimeout或类似的东西。 - Aileron79
2
@Aileron79,所提供的示例使用的是Entity Framework Core,而不是Entity Framework 6。 - Keegan Kozler
请注意,在文件顶部添加“using Microsoft.EntityFrameworkCore”以获取此扩展方法。 - Daniel
我无法想象这对大多数需要执行此操作的人来说是最佳解决方案。如果您需要增加超时时间,很可能是因为您有一小部分查询预计会在默认情况下超时(出于任何原因-不评判!)。如果您的其余查询都已经完全优化,您可以使用1天的超时时间而不会注意到,但这会剥夺数据库对那些您尚不知道效率低下的查询的抱怨能力。对于较长的超时时间(例如5分钟),更大的问题是要先考虑其他答案,不要急于找到一个可能会后悔的修复方法。 - undefined

72

您可以通过您的上下文进行更改。

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

这对于EF6 Core来说不起作用。或者我做了其他的事情。我的意思是,例如执行SaveChanges()需要10秒钟,当我将超时设置为1秒时,它仍然不会抛出错误,也许您知道该如何设置? - ruddnisrus
注意:如果您正在为注入的上下文的Database属性设置超时,请确保添加using Microsoft.EntityFrameworkCore;,因为SetCommandTimeout是一个扩展方法。 - undefined

37

如果您想为一个Context实例仅临时增加超时时间。

比如对于1个请求(默认Scoped上下文生命周期)

在长时间运行的查询之前更改此设置:

Context.Database.SetCommandTimeout(TimeSpan.FromMinutes(20))

通过使用有限作用域,您只需在一次指定超时时间,而不必在任何后续服务构造函数注入中指定它。


1
感谢您的回答,它特别解决了我对于这种更改的生命周期的担忧。然而,我很好奇您是如何知道SetCommandTimeout中使用的值仅限于通过 DI 提供的一个上下文,而不是适用于每个上下文实例?您是否有参考文献来支持这一点? - Blair Allen
我应该把这行代码放在哪里?在控制器的IActionResult内部,dbContext语句的using内部,还是在dbContext的构造函数内部? - usernumber124153
@Blair好问题!DbContext.Database的文档明确指出为此上下文创建一个数据库实例,允许对底层数据库进行创建/删除/存在检查,所以是针对一个上下文的。https://learn.microsoft.com/en-us/dotnet/api/system.data.entity.dbcontext.database?view=entity-framework-6.2.0 - undefined

17
在EF Core 3及以上版本中,您现在可以通过连接字符串进行配置。但是,您需要从'System.Data.SqlClient'迁移到'Microsoft.Data.SqlClient'。将System.Data.SqlClient替换为Microsoft.Data.SqlClient版本2.1.0或更高版本。然后,在连接字符串中添加命令超时即可。
"Data Source=SqlExpress;Initial Catalog=YourDatabase;Integrated Security=true;Command Timeout=300"

这将仅适用于 Microsoft.Data.SqlClient 2.1.0 或更高版本,如果您尝试使用 System.Data.SqlClient 进行此操作,将会出现异常。


2
请注意4.0版本的重大变化,Encrypt=true现在是默认设置。在此之前,System..SqlClient默认情况下不会尝试为mssql连接使用TLS。请参考以下链接:https://github.com/dotnet/SqlClient/blob/main/CHANGELOG.md#preview-release-400-preview1212372---2021-08-25 - yzorg
如果服务器使用内部证书,或者您从域外连接到加入域的服务器(例如我的情况是 Kubernetes 托管应用程序),则 Encrypt=true 可能会导致连接开始失败。 - yzorg

7
更好的选择是在上下文设置期间使用CommandTimeout,例如:
public class DbConnect: IConnnectDb
{
    private dbentitient _context;

    // inject this to a db entity from constructor. 

    //inside each method now use the follow before u actually run the query to db.  

    _context.Database.SetCommandTimeout(400);
}     

注意:EF Core 只会执行少于 100 秒的查询。如果超过了这个时间,它会不断重试,你永远看不到结果。
这是我的经验,所以如果你能解决这个问题,请让我知道。 EF Core 1.0 的超时时间甚至比 EF Core 2.0 更短。

1
这似乎不太对。EF Core 默认情况下不会重试任何操作? - Kyberias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接