web-dev-qa-db-ja.com

DbContextにCommandTimeoutを設定する方法は?

DbContextにCommandTimeoutを設定する方法を探しています。検索後、DbContextをObjectContextにキャストし、objectContextのCommandTimeoutプロパティの値を設定することで方法を見つけました。

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

ただし、DbContextを使用する必要があります。

56
Yara

メソッドで動作します。

またはサブクラス化します( 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;
  }
}
89
Jonas Lincoln
var ctx = new DbContext();
ctx.Database.CommandTimeout = 120;
22
Perry Tribolet

これはあなたを助けるかもしれません。

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

後で変更を失うことはないので、.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;
        }
6
Mike Burger

EDMXファイルを使用するときにこの問題を解決した方法を次に示します。このソリューションは、デフォルトのT4テンプレートを変更して、生成されたクラスがデフォルトのコマンドタイムアウトとそれを変更するプロパティを指定するカスタムDbContextクラスから継承するようにします。

Visual Studio 2012およびEF 5.0を使用しています。他のバージョンでは経験が異なる場合があります。

カスタム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;
        }
    }
}

これにはオプション機能があります。デフォルトのコマンドタイムアウトをハードコーディングしていません。代わりに、設定ファイルの値を変更できるように、プロジェクト設定からロードしています。プロジェクト設定のセットアップおよび使用方法は、この回答の範囲外です。

また、接続文字列または接続文字列名をハードコーディングしていません。生成されたコンテキストクラスによってコンストラクタに既に渡されているため、ここでハードコードすることは意味がありません。これは新しいことではありません。 EDMXファイルは既に次のコンストラクタを生成しているため、値を渡すだけです。

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

(これにより、構成ファイルから "MyEntities"という名前の接続文字列を読み込むようEFに指示されます。)

ObjectContextがnullの場合、カスタム例外をスローしています。私はそれがこれからになるとは思いませんが、NullReferenceExceptionを取得するよりも意味があります。

ObjectContextをフィールドに保存して、プロパティにアクセスしてデフォルトをオーバーライドできるようにします。

エンティティコンテキストT4テンプレートの変更

ソリューションエクスプローラーで、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に戻すことができます。

3
Glazed

拡張アプローチが好きです:

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

そして単純に

((IObjectContextAdapter)cx).ObjectContext.SetCommandTimeout(300);
2
Stefan Michev

それが役立つ場合、これはVB.Netソリューションです:

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

このようなグローバルな設定ではなく、単一のコマンドのタイムアウトを設定する例を探してここに来ました。

私がこれをどのように達成したかの例を持っているとおそらく助けになると思います:

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();
0
Elliot Harper