DbContextにCommandTimeoutを設定する方法を探しています。検索後、DbContextをObjectContextにキャストし、objectContextのCommandTimeoutプロパティの値を設定することで方法を見つけました。
var objectContext = (this.DbContext as IObjectContextAdapter).ObjectContext;
ただし、DbContextを使用する必要があります。
メソッドで動作します。
またはサブクラス化します( msdn forum から)
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;
}
}
var ctx = new DbContext();
ctx.Database.CommandTimeout = 120;
これはあなたを助けるかもしれません。
public class MyContext : DbContext
{
public MyContext () : base(ContextHelper.CreateConnection("my connection string"), true)
{
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
}
}
後で変更を失うことはないので、.ttファイルを変更するとうまくいくことがわかります。
次の行を追加します。
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
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))
生成されたContext.csに表示されるはずです。
public MyEntities()
: base("name=MyEntities")
{
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;
}
EDMXファイルを使用するときにこの問題を解決した方法を次に示します。このソリューションは、デフォルトのT4テンプレートを変更して、生成されたクラスがデフォルトのコマンドタイムアウトとそれを変更するプロパティを指定するカスタムDbContextクラスから継承するようにします。
Visual Studio 2012およびEF 5.0を使用しています。他のバージョンでは経験が異なる場合があります。
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;
}
}
}
これにはオプション機能があります。デフォルトのコマンドタイムアウトをハードコーディングしていません。代わりに、設定ファイルの値を変更できるように、プロジェクト設定からロードしています。プロジェクト設定のセットアップおよび使用方法は、この回答の範囲外です。
また、接続文字列または接続文字列名をハードコーディングしていません。生成されたコンテキストクラスによってコンストラクタに既に渡されているため、ここでハードコードすることは意味がありません。これは新しいことではありません。 EDMXファイルは既に次のコンストラクタを生成しているため、値を渡すだけです。
public MyEntities()
: base("name=MyEntities")
{
}
(これにより、構成ファイルから "MyEntities"という名前の接続文字列を読み込むようEFに指示されます。)
ObjectContext
がnullの場合、カスタム例外をスローしています。私はそれがこれからになるとは思いませんが、NullReferenceException
を取得するよりも意味があります。
ObjectContext
をフィールドに保存して、プロパティにアクセスしてデフォルトをオーバーライドできるようにします。
ソリューションエクスプローラーで、EDMXファイルを展開して、T4テンプレートを表示します。拡張子は.ttです。
「MyModel.Context.tt」ファイルをダブルクリックして開きます。行57の周りにこれが表示されるはずです。
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
このテンプレート行は、DbContextを継承する「MyEntities」クラスのクラス定義を生成します。
代わりに、生成されたクラスがCustomDbContextを継承するように行を変更します。
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : CustomDbContext
このファイルを保存するとすぐに、クラスが再生成されます。そうでない場合は、EDMXファイルを右クリックして[カスタムツールの実行]を選択します。 EDMXファイルの下にある「MyModel.Context.tt」ファイルを展開すると、「MyModel.Context.cs」が表示されます。それが生成されたファイルです。それを開くと、CustomDbContext
を継承していることがわかります。
public partial class MyEntities : CustomDbContext
これですべてです。
コンテキストクラスをDbContext
からCustomDbContext
に変更すると、「読み取り/書き込みアクションとビューを持つコントローラー」を使用して新しいMVCコントローラークラスを追加しようとすると、Visual Studioでエラーが発生します。 Entity Frameworkを使用」テンプレート。 「サポートされていないコンテキストタイプ」と表示されます。これを回避するには、生成された "MyModel.Context.cs"クラスを開き、継承する型を一時的にDbContext
に戻します。新しいコントローラーを追加した後、CustomDbContext
に戻すことができます。
拡張アプローチが好きです:
public static class DbContextExtensions
{
public static void SetCommandTimeout(this ObjectContext dbContext,
int TimeOut)
{
dbContext.CommandTimeout = TimeOut;
}
}
そして単純に
((IObjectContextAdapter)cx).ObjectContext.SetCommandTimeout(300);
それが役立つ場合、これはVB.Netソリューションです:
Dim objectContext As Objects.ObjectContext = CType(Me,IObjectContextAdapter).ObjectContext
objectContext.commandTimeout = connectionTimeout
このようなグローバルな設定ではなく、単一のコマンドのタイムアウトを設定する例を探してここに来ました。
私がこれをどのように達成したかの例を持っているとおそらく助けになると思います:
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();