エンティティフレームワークのタイムアウト


324

完了までに30秒以上かかる関数のインポートを使用すると、Entity Framework(EF)を使用してタイムアウトが発生します。私は以下を試しましたが、この問題を解決できませんでした:

ここで提案されているように、EDMXファイルを持つプロジェクトのApp.ConfigファイルのDefault Command Timeout=300000接続文字列に追加しました

これは私の接続文字列は次のようになります。

<add 
    name="MyEntityConnectionString" 
    connectionString="metadata=res://*/MyEntities.csdl|res://*/MyEntities.ssdl|
       res://*/MyEntities.msl;
       provider=System.Data.SqlClient;provider connection string=&quot;
       Data Source=trekdevbox;Initial Catalog=StarTrekDatabase;
       Persist Security Info=True;User ID=JamesTKirk;Password=IsFriendsWithSpock;
       MultipleActiveResultSets=True;Default Command Timeout=300000;&quot;"
    providerName="System.Data.EntityClient" />

私のリポジトリでCommandTimeoutを次のように直接設定してみました:

private TrekEntities context = new TrekEntities();

public IEnumerable<TrekMatches> GetKirksFriends()
{
    this.context.CommandTimeout = 180;
    return this.context.GetKirksFriends();
}

EFがタイムアウトしないようにするには、他に何ができますか?これは非常に大きなデータセットでのみ発生します。すべてが小さなデータセットで正常に動作します。

ここに私が得ているエラーの一つがあります:

System.Data.EntityCommandExecutionException:コマンド定義の実行中にエラーが発生しました。詳細については、内部の例外を参照してください。---> System.Data.SqlClient.SqlException:タイムアウトの期限が切れました。操作が完了する前にタイムアウト期間が経過したか、サーバーが応答していません。


OK-私はこれを動作させました、そしてそれは起こったことはばかげています。接続文字列とDefault Command Timeout=300000CommandTimeoutの両方を180に設定しDefault Command Timeoutました。接続文字列からを削除すると、動作しました。したがって、答えは、次のようにコンテキストオブジェクトのリポジトリのCommandTimeoutを手動で設定することです。

this.context.CommandTimeout = 180;

どうやら接続文字列でタイムアウト設定を設定しても、影響はありません。


削除&quot; 接続文字列から
ブライアンウェブスター

これも参照してください
net

5
@ hamlin11 EF接続文字列では、接続文字列とEFメタデータの部分を定義するために必要です。&quot;文字列のままにします。
Chev

2
私の提案は、タイムアウトを増やす前に、EFがタイムアウトする理由を最初に調査することです。今回のケースではNONCLUSTERED、一部のテーブルにインデックスを追加する必要があることに気づき、タイムアウトの問題が解決しました。
zulucoda 2014年

SQLタイムアウトの問題についてMSサポートと協力しています-これは、DBがSQL Azureでホストされている場合です。すべてのAzure PaaSサービス(PaaS WebサイトやSQL Azureなど)には、230秒のユニバーサルタイムアウトがあると言われました。タイムアウトを手動で設定した場合でも、これが常に優先されます。これは、マルチテナントのPaaSインフラストラクチャのリソースを保護するためです。
Ian Robertson

回答:


552

EF接続文字列内でデフォルトのコマンドタイムアウトを指定することには既知のバグがあります。

http://bugs.mysql.com/bug.php?id=56806

接続文字列から値を削除し、データコンテキストオブジェクト自体に設定します。これは、接続文字列から競合する値を削除した場合に機能します。

Entity Framework Core 1.0:

this.context.Database.SetCommandTimeout(180);

エンティティフレームワーク6:

this.context.Database.CommandTimeout = 180;

エンティティフレームワーク5:

((IObjectContextAdapter)this.context).ObjectContext.CommandTimeout = 180;

Entity Framework 4以下:

this.context.CommandTimeout = 180;

5
どうすればedmxを使用してこれを実現できますか?
イロエル2014年

2
これはどのバージョンのEntityFrameworkで修正されていますか?EFバグが見つかりません。
rudimenter

7
私はこれがバグだとは思わないが、設計によるものです。リンクの
Mick P

3
一部の設定はmsで、一部はs なので、ここで調べたところ、CommandTimeoutは秒単位でした。
JabberwockyDecompiler 2015年

6
Entity Frameworkの7では、あなたはDbContext / IdentityDbContextのコンストラクタでこれを設定することができますthis.Database.SetCommandTimeout(180);
トーマス・ハグストローム

101

DbContextを使用している場合は、次のコンストラクタを使用してコマンドのタイムアウトを設定します。

public class MyContext : DbContext
{
    public MyContext ()
    {
        var adapter = (IObjectContextAdapter)this;
        var objectContext = adapter.ObjectContext;
        objectContext.CommandTimeout = 1 * 60; // value in seconds
    }
}

3
@ErickPetruなので、簡単に別の分数に変更できます:)。また、コンパイラーがその乗算を最適化したとしても、驚くことはありません!
Joel Verhagen 2013

2
@JoelVerhagen、驚かないでください。自動最適化がいつ発生するかについての適切な説明は次のとおりです:stackoverflow.com/questions/160848/…。この場合、(2つのリテラル値であるため)発生することもあると思いますが、正直なところ、コードはこのように奇妙だと思います。
Erick Petrucelli 2013

33
えっ...子供たちは飢えています...誰が1 * 60を気にしますか?
Timmerz 2013

9
@ErikPetru、これは実際には非常に一般的な方法であり、コードを読みやすくしています。
Calvin

私のDbContext派生クラスがedmxファイルから自動生成された場合、これを処理する最良の方法は何ですか?
マットバーランド2014

41

DbContextとEF v6 + を使用している場合は、代わりに以下を使用できます。

this.context.Database.CommandTimeout = 180;

13

通常、トランザクション内で操作を処理します。私が経験したように、コンテキストコマンドのタイムアウトを設定するだけでは十分ではありませんが、トランザクションにはタイムアウトパラメータを指定したコンストラクタが必要です。正しく機能させるには、両方のタイムアウト値を設定する必要がありました。

int? prevto = uow.Context.Database.CommandTimeout;
uow.Context.Database.CommandTimeout = 900;
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromSeconds(900))) {
...
}

関数の最後に、コマンドタイムアウトをprevtoの以前の値に戻しました。

EF6の使用


まったく良いアプローチではありません。以前はたくさんのトランザクションスコープを追加していたので、プロジェクトではそれが悪夢になりました。最終的に、EF 6+では、すべてのトランザクションスコープを単一のSAVEChanges()に置き換えました。このチェックcoderwall.com/p/jnniww/...
ムーンズ

この回答は投票数が多いはずです。タイムアウトを増やすためにさまざまな方法を試しましたが、コンテキストコマンドタイムアウトとトランザクションスコープの両方を設定した場合にのみ機能しました。
ギャング

3

これは非常に古いスレッドが実行されていることを知っていますが、それでもEFはこれを修正していません。自動生成DbContextを使用している人は、次のコードを使用してタイムアウトを手動で設定できます。

public partial class SampleContext : DbContext
{
    public SampleContext()
        : base("name=SampleContext")
    {
        this.SetCommandTimeOut(180);
    }

    public void SetCommandTimeOut(int Timeout)
    {
        var objectContext = (this as IObjectContextAdapter).ObjectContext;
        objectContext.CommandTimeout = Timeout;
    }

3

私のようなEntity Frameworkを使用している場合は、次のようにスタートアップクラスのタイムアウトを定義する必要があります。

 services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), o => o.CommandTimeout(180)));

1

これは私が出資したものです。多分それは誰かを助けるでしょう:

だからここに行きます:

EFでLINQを使用して、次のようにリストに含まれる正確な要素を探している場合:

await context.MyObject1.Include("MyObject2").Where(t => IdList.Contains(t.MyObjectId)).ToListAsync();

IdListに複数のIDが含まれるまで、すべてが正常に行われます。

リストにIDが1つしかない場合、「タイムアウト」の問題が発生します。この問題を解決するには、if条件を使用してIdListのIDの数を確認します。

例:

if (IdList.Count == 1)
{
    result = await entities. MyObject1.Include("MyObject2").Where(t => IdList.FirstOrDefault()==t. MyObjectId).ToListAsync();
}
else
{
    result = await entities. MyObject1.Include("MyObject2").Where(t => IdList.Contains(t. MyObjectId)).ToListAsync();
}

説明:

SQLプロファイラーを使用して、Entity frameeorkによって生成されたSelectステートメントを確認してください。…

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.