C# 如何为 DbContext 设置 CommandTimeout?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10549640/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 14:16:01  来源:igfitidea点击:

How to set CommandTimeout for DbContext?

c#entity-framework-4dbcontextcommand-timeout

提问by Yara

I am looking a way to set CommandTimeout for DbContext. After searching I found the way by casting DbContext into ObjectContext and setting value for CommandTimeout property of objectContext.

我正在寻找一种为 DbContext 设置 CommandTimeout 的方法。搜索后,我通过将 DbContext 转换为 ObjectContext 并为 objectContext 的 CommandTimeout 属性设置值找到了方法。

var objectContext = (this.DbContext as IObjectContextAdapter).ObjectContext;

But I have to work with DbContext.

但我必须使用 DbContext。

采纳答案by Jonas Lincoln

It will work with your method.

它将适用于您的方法。

Or subclass it (from msdn forum)

或将其子类化(来自msdn 论坛

public class YourContext : DbContext
{
  public YourContext()
    : base("YourConnectionString")
  {
    // Get the ObjectContext related to this DbContext
    var objectContext = (this as IObjectContextAdapter).ObjectContext;

    // Sets the command timeout for all the commands
    objectContext.CommandTimeout = 120;
  }
}

回答by Rejeesh

This may help you.

这可能对你有帮助。

public class MyContext : DbContext
{    
    public MyContext () : base(ContextHelper.CreateConnection("my connection string"), true)
    {
        ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
    }
}

回答by Exatex

If it can help, this is the VB.Net solution:

如果有帮助,这是 VB.Net 解决方案:

Dim objectContext As Objects.ObjectContext = CType(Me,IObjectContextAdapter).ObjectContext
objectContext.commandTimeout = connectionTimeout

回答by Stefan Michev

I like the extension approach:

我喜欢扩展方法:

public static class DbContextExtensions
{
   public static void SetCommandTimeout(this ObjectContext dbContext,
       int TimeOut)
   {
       dbContext.CommandTimeout = TimeOut;
   }
}

and then simply

然后简单地

((IObjectContextAdapter)cx).ObjectContext.SetCommandTimeout(300);

回答by Glazed

Here's how I solved this problem when using an EDMX file. This solution changes the default T4 template to make the generated class inherit from a custom DbContext class, which specifies a default command timeout, and a property to change it.

这是我在使用 EDMX 文件时解决这个问题的方法。此解决方案更改默认 T4 模板,使生成的类继承自自定义 DbContext 类,该类指定默认命令超时和更改它的属性。

I'm using Visual Studio 2012 and EF 5.0. Your experience may differ with other versions.

我使用的是 Visual Studio 2012 和 EF 5.0。您的体验可能与其他版本不同。

Create a custom DbContext class

创建自定义 DbContext 类

public class CustomDbContext : DbContext
{
    ObjectContext _objectContext;

    public CustomDbContext( string nameOrConnectionString )
        : base( nameOrConnectionString )
    {
        var adapter = (( IObjectContextAdapter) this);

        _objectContext = adapter.ObjectContext;

        if ( _objectContext == null )
        {
            throw new Exception( "ObjectContext is null." );    
        }

        _objectContext.CommandTimeout = Settings.Default.DefaultCommandTimeoutSeconds;
    }

    public int? CommandTimeout
    {
        get
        {
            return _objectContext.CommandTimeout;
        }
        set
        {
            _objectContext.CommandTimeout = value;
        }
    }
}

This has an optional feature: I'm not hard-coding the default command timeout. Instead, I'm loading it from the project settings so that I can change the value in a config file. How to setup and use project settings is not in the scope of this answer.

这有一个可选功能:我没有对默认命令超时进行硬编码。相反,我从项目设置中加载它,以便我可以更改配置文件中的值。如何设置和使用项目设置不在本答案的范围内。

I'm also not hard-coding the connection string or connection string name. It's already passed into the constructor by the generated context class, so it makes no sense to hard-code it here. This is nothing new; the EDMX file already generates the following constructor for you, so we are just passing along the value.

我也没有对连接字符串或连接字符串名称进行硬编码。它已经由生成的上下文类传递给构造函数,因此在这里对其进行硬编码是没有意义的。这不是什么新鲜事。EDMX 文件已经为您生成了以下构造函数,因此我们只是传递值。

public MyEntities()
    : base("name=MyEntities")
{
}

(This instructs EF to load the connection string named "MyEntities" from the config file.)

(这会指示 EF 从配置文件中加载名为“MyEntities”的连接字符串。)

I'm throwing a custom exception if the ObjectContextis ever null. I don't think it ever will be, but it's more meaningful than getting a NullReferenceException.

如果ObjectContext为空,我将抛出一个自定义异常。我认为它永远不会,但它比获得NullReferenceException.

I store the ObjectContextin a field so that I can make a property to access it to override the default.

我将 存储ObjectContext在一个字段中,以便我可以创建一个属性来访问它以覆盖默认值。

Modifying the entity context T4 template

修改实体上下文 T4 模板

In the Solution Explorer, expand the EDMX file so that you see the T4 templates. They have a .tt extension.

在解决方案资源管理器中,展开 EDMX 文件,以便您看到 T4 模板。他们有一个 .tt 扩展名。

Double click the "MyModel.Context.tt" file to open it. Around line 57 you should see this:

双击“MyModel.Context.tt”文件将其打开。在第 57 行左右,您应该会看到:

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext

This template line generates the class definition of your "MyEntities" class, which inherits DbContext.

此模板行生成继承 DbContext 的“MyEntities”类的类定义。

Change the line so that the generated class inherits CustomDbContext, instead:

更改该行,以便生成的类继承 CustomDbContext,而不是:

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : CustomDbContext

As soon as you save this file it should regenerate the class. If not, you can right-click the EDMX file and select "Run Custom Tool". If you expand the "MyModel.Context.tt" file under your EDMX file, you will see "MyModel.Context.cs". That's the generated file. Open it, and you should see that it now inherits CustomDbContext.

保存此文件后,它应该会重新生成该类。如果没有,您可以右键单击 EDMX 文件并选择“运行自定义工具”。如果您展开 EDMX 文件下的“MyModel.Context.tt”文件,您将看到“MyModel.Context.cs”。这就是生成的文件。打开它,您应该会看到它现在继承了CustomDbContext.

public partial class MyEntities : CustomDbContext

That's all there is to it.

这里的所有都是它的。

Issues

问题

Once you change the context class from DbContextto CustomDbContext, Visual Studio will give you an error if you try to add a new MVC controller class using the "Controller with read/write actions and views, using Entity Framework" template. It will say "Unsupported context type.". To get around this, open the generated "MyModel.Context.cs" class, and temporarily change the type it inherits back to DbContext. After adding your new controller, you can change it back to CustomDbContext.

一旦您将上下文类从 更改DbContextCustomDbContext,如果您尝试使用“具有读/写操作和视图的控制器,使用实体框架”模板添加新的 MVC 控制器类,Visual Studio 将给您一个错误。它会说“不支持的上下文类型。”。要解决此问题,请打开生成的“MyModel.Context.cs”类,并将其继承的类型暂时更改回DbContext. 添加新控制器后,您可以将其改回CustomDbContext.

回答by Mike Burger

I find that changing the .tt file works for me as I don't lose the change later on:

我发现更改 .tt 文件对我有用,因为我以后不会丢失更改:

Add this line:

添加这一行:

((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;

Right after the DbContext creator and before the !loader.IsLazy construct:

在 DbContext 创建者之后和 !loader.IsLazy 构造之前:

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{
    public <#=code.Escape(container)#>()
        : base("name=<#=container.Name#>")
    {
        ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
<#
if (!loader.IsLazyLoadingEnabled(container))

It should then appear in your generated Context.cs:

然后它应该出现在您生成的 Context.cs 中:

public MyEntities()
            : base("name=MyEntities")
        {
            ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
        }

回答by Perry Tribolet

var ctx = new DbContext();
ctx.Database.CommandTimeout = 120;

回答by Elliot Harper

I came here looking for an example of setting the timeout for a single command rather than such a global setting.

我来这里是为了寻找一个为单个命令设置超时的示例,而不是这样一个全局设置。

I figure that it will probably help someone to have an example of how I achieved this:

我认为它可能会帮助某人举例说明我是如何实现这一目标的:

var sqlCmd = new SqlCommand(sql, context.Database.Connection as SqlConnection);
sqlCmd.Parameters.Add(idParam);
sqlCmd.CommandTimeout = 90;

if (sqlCmd.Connection.State == System.Data.ConnectionState.Closed)
{
    sqlCmd.Connection.Open();
}
sqlCmd.ExecuteNonQuery();
sqlCmd.Connection.Close();