Legen Sie das Datenbankzeitlimit in Entity Framework fest

164

Mein Befehl läuft ständig ab, daher muss ich den Standardwert für das Zeitlimit für Befehle ändern.

Ich habe gefunden myDb.Database.Connection.ConnectionTimeout, aber es ist readonly.

Wie kann ich das Befehlszeitlimit in Entity Framework 5 festlegen ?

James
quelle
20
Zu Ihrer Information, auf EF6, Database.CommandTimeoutist nicht mehr schreibgeschützt
itsho
2
@itsho Er sprach über Database.Connection.ConnectionTimeout. Wie auch immer, ich würde sagen, dass dies Database.CommandTimeoutdas Richtige ist, wenn Ihre Abfrage eine Zeitüberschreitung aufweist (Ausnahme System.Data.Entity.Core.EntityCommandExecutionExceptionenthalten System.Data.SqlClient.SqlException: Timeout expired.).
David Ferenczy Rogožan
2
Mögliches Duplikat von Entity Framework Timeouts
Tim Pohlmann
1
Ich gehe davon aus, dass Ihnen das CONNECTION-Timeout eigentlich egal ist, sondern dass Sie das COMMAND-Timeout anpassen möchten.
Worthy7

Antworten:

199

Versuchen Sie dies in Ihrem Kontext:

public class MyDatabase : DbContext
{
    public MyDatabase ()
        : base(ContextHelper.CreateConnection("Connection string"), true)
    {
        ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 180;
    }
}

Wenn Sie das Zeitlimit in der Verbindungszeichenfolge definieren möchten, verwenden Sie den Connection TimeoutParameter wie in der folgenden Verbindungszeichenfolge:

<connectionStrings>

<add name="AdventureWorksEntities"
connectionString="metadata=.\AdventureWorks.csdl|.\AdventureWorks.ssdl|.\AdventureWorks.msl;
provider=System.Data.SqlClient;provider connection string='Data Source=localhost;
Initial Catalog=AdventureWorks;Integrated Security=True;Connection Timeout=60;
multipleactiveresultsets=true'" providerName="System.Data.EntityClient" />

</connectionStrings>

Quelle: Gewusst wie: Definieren Sie die Verbindungszeichenfolge

Leniel Maccaferri
quelle
1
Ich würde empfehlen, die Verbindungszeichenfolgenversion so zu verwenden, als ob Sie versuchen, ObjectContextin diesem Konstruktor auf die zuzugreifen. Manchmal schlagen die PowerShell / NuGet-Konsolenbefehle zirkulär fehl .
Kevin Gorski
130
Verbindungs-Timeout und CommandTimeout und zwei verschiedene Dinge. Die Einstellung für die Verbindungszeichenfolge "Verbindungszeitlimit" hat keinen Einfluss auf die Ausführungsdauer des Befehls (CommandTimeout).
Clay Lenhart
3
Mein Problem war ein bisschen anders. Ich habe während der Migrationen eine Auszeit bekommen. EF hat eine ähnliche Eigenschaft, die für die Verwendung während Migrationen festgelegt werden muss: msdn.microsoft.com/en-us/library/…
Karsten
2
Je nachdem, welche Version von EF Sie verwenden, finden Sie in dieser Antwort ein Gefühl für die verschiedenen APIs beim Angeben der CommandTimeout-Eigenschaft.
Jim Aho
1
Funktioniert bei mir nicht (Verbindung gegen Befehl ist nicht dasselbe, was ich vermute). Dieser Beitrag löste es durch stackoverflow.com/questions/6232633/entity-framework-timeouts
Jezbers
181

Sie können verwenden DbContext.Database.CommandTimeout = 180;

Es ist ziemlich einfach und keine Besetzung erforderlich.

Vu Nguyen
quelle
1
Sehr nützlich für uns, die Fluent APIForm von EF verwenden.
GoldBishop
20

Mein Teilkontext sieht aus wie:

public partial class MyContext : DbContext
{
    public MyContext (string ConnectionString)
        : base(ConnectionString)
    {
        this.SetCommandTimeOut(300);
    }

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

Ich habe die SetCommandTimeOutÖffentlichkeit verlassen, sodass nur die Routinen, die ich für eine lange Zeit (mehr als 5 Minuten) benötige, anstelle einer globalen Zeitüberschreitung geändert werden.

Erik Philips
quelle
9

Im generierten Konstruktorcode sollte es aufrufen OnContextCreated()

Ich habe diese Teilklasse hinzugefügt, um das Problem zu lösen:

partial class MyContext: ObjectContext
{
    partial void OnContextCreated()
    {
        this.CommandTimeout = 300;
    }
}
Owen
quelle
8

Ich habe Ronnies Antwort mit einer fließenden Implementierung erweitert, damit Sie sie folgendermaßen verwenden können:

dm.Context.SetCommandTimeout(120).Database.SqlQuery...

public static class EF
{
    public static DbContext SetCommandTimeout(this DbContext db, TimeSpan? timeout)
    {
        ((IObjectContextAdapter)db).ObjectContext.CommandTimeout = timeout.HasValue ? (int?) timeout.Value.TotalSeconds : null;

        return db;
    }

    public static DbContext SetCommandTimeout(this DbContext db, int seconds)
    {
        return db.SetCommandTimeout(TimeSpan.FromSeconds(seconds));
    } 
}
Timmerz
quelle
8

Für die Datenbank zuerst Ansatz:

Wir können es weiterhin in einem Konstruktor festlegen , indem wir die ContextName.Context.tt T4-Vorlage folgendermaßen überschreiben :

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{
    public <#=code.Escape(container)#>()
        : base("name=<#=container.Name#>")
    {
        Database.CommandTimeout = 180;
<#
if (!loader.IsLazyLoadingEnabled(container))
{
#>
        this.Configuration.LazyLoadingEnabled = false;
<#
}

Database.CommandTimeout = 180; ist die akute Veränderung.

Die generierte Ausgabe lautet wie folgt:

public ContextName() : base("name=ContextName")
{
    Database.CommandTimeout = 180;
}

Wenn Sie Ihr Datenbankmodell ändern, bleibt diese Vorlage erhalten, die aktuelle Klasse wird jedoch aktualisiert.

Christian Gollhardt
quelle
Gibt es eine Möglichkeit, das Zeitlimit in der Vorlage mithilfe einer Konfigurationsdatei anzugeben?
Shas
1
Ich bin mir nicht sicher, ob etwas eingebaut ist (ich konnte nichts finden). Aber anstatt 180 fest zu codieren, können Sie System.Configuration.ConfigurationManager.AppSettings["keyname"]@shas
Christian Gollhardt
7

Wie andere Antworten, jedoch als Erweiterungsmethode:

static class Extensions
{
    public static void SetCommandTimeout(this IObjectContextAdapter db, TimeSpan? timeout)
    {
        db.ObjectContext.CommandTimeout = timeout.HasValue ? (int?) timeout.Value.TotalSeconds : null;
    }
}
Ronnie Overby
quelle
und wie nenne ich diese Erweiterungsmethode?
Wanderson López
1

Ich bin gerade auf dieses Problem gestoßen und habe es durch Aktualisieren meiner Anwendungskonfigurationsdatei behoben. Geben Sie für die betreffende Verbindung "Verbindungszeitlimit = 60" an (ich verwende das Entity Framework Version 5.0.0.0).

ConnectionTimeout-Einstellung

Andrew Burrow
quelle
0

Sie können dies einfach verwenden:
dbContext.Database.SetCommandTimeout(300);

Hassan Muhammad Saad
quelle