如何为DbContext设置CommandTimeout?
我正在寻找一种方法来为DbContext设置CommandTimeout。 search后,我find了通过将DbContext投射到ObjectContext并为ObjectContext的CommandTimeout属性设置值的方式。
var objectContext = (this.DbContext as IObjectContextAdapter).ObjectContext;
但是我必须使用DbContext。
它将与你的方法一起工作。
或者子类(从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; } }
这可能会帮助你。
public class MyContext : DbContext { public MyContext () : base(ContextHelper.CreateConnection("my connection string"), true) { ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300; } }
var ctx = new DbContext(); ctx.Database.CommandTimeout = 120;
我发现改变.tt文件适用于我,因为稍后我不会丢失更改:
添加这一行:
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
紧跟在DbContext创build者之后,在!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))
它应该出现在你生成的Context.cs中:
public MyEntities() : base("name=MyEntities") { ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300; }
我喜欢扩展方法:
public static class DbContextExtensions { public static void SetCommandTimeout(this ObjectContext dbContext, int TimeOut) { dbContext.CommandTimeout = TimeOut; } }
然后简单地
((IObjectContextAdapter)cx).ObjectContext.SetCommandTimeout(300);
如果可以帮助,这是VB.Net解决scheme:
Dim objectContext As Objects.ObjectContext = CType(Me,IObjectContextAdapter).ObjectContext objectContext.commandTimeout = connectionTimeout
以下是我在使用EDMX文件时如何解决这个问题。 此解决scheme更改了默认的T4模板,以使生成的类从自定义的DbContext类(它指定默认的命令超时)以及用于更改它的属性inheritance。
我正在使用Visual Studio 2012和EF 5.0。 您的体验可能与其他版本不同。
创build一个自定义的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; } } }
这有一个可选的function:我没有硬编码的默认命令超时。 相反,我从项目设置加载它,以便我可以更改configuration文件中的值。 如何设置和使用项目设置不在此答案的范围内。
我也没有硬编码的连接string或连接string名称。 它已经通过生成的上下文类传入构造函数,所以在这里对它进行硬编码是没有意义的。 这不是什么新鲜事。 EDMX文件已经为您生成了以下构造函数,所以我们只是传递值。
public MyEntities() : base("name=MyEntities") { }
(这指示EF从configuration文件中加载名为“MyEntities”的连接string。)
如果ObjectContext
是空的,我抛出一个自定义exception。 我不认为它会永远是,但它比得到一个NullReferenceException
更有意义。
我将ObjectContext
存储在一个字段中,这样我可以创build一个属性来访问它来覆盖默认值。
修改实体上下文T4模板
在解决scheme资源pipe理器中,展开EDMX文件,以便看到T4模板。 他们有一个.tt扩展名。
双击“MyModel.Context.tt”文件将其打开。 在第57行左右你应该看到这个:
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
该模板行生成inheritanceDbContext的“MyEntities”类的类定义。
更改行,以便生成的类inheritanceCustomDbContext,而不是:
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : CustomDbContext
只要你保存这个文件,它应该重新生成类。 如果没有,您可以右键单击EDMX文件并select“运行自定义工具”。 如果您在EDMX文件下展开“MyModel.Context.tt”文件,您将看到“MyModel.Context.cs”。 这是生成的文件。 打开它,你会看到它现在inheritance了CustomDbContext
。
public partial class MyEntities : CustomDbContext
这里的所有都是它的。
问题
一旦将上下文类从DbContext
为CustomDbContext
,如果尝试使用“具有读/写操作和视图的控制器,使用entity framework”模板添加新的MVC控制器类,Visual Studio将会出错。 它会说“不支持的上下文types”。 为了解决这个问题,打开生成的“MyModel.Context.cs”类,并临时将其inheritance的types更改回DbContext
。 添加新控制器后,可以将其更改回CustomDbContext
。
我来到这里寻找一个设置单个命令超时的例子,而不是这样一个全局设置。
我认为这可能会帮助某个人举例说明我是如何实现这一目标的:
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();