Timeouts für Entity Framework

324

Ich erhalte Zeitüberschreitungen mit dem Entity Framework (EF), wenn ein Funktionsimport verwendet wird, dessen Abschluss mehr als 30 Sekunden dauert. Ich habe Folgendes versucht und konnte dieses Problem nicht beheben:

Ich Default Command Timeout=300000habe die Verbindungszeichenfolge in der App.Config- Datei in dem Projekt hinzugefügt , das die EDMX-Datei enthält, wie hier vorgeschlagen .

So sieht meine Verbindungszeichenfolge aus:

<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" />

Ich habe versucht, das CommandTimeout in meinem Repository direkt wie folgt festzulegen:

private TrekEntities context = new TrekEntities();

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

Was kann ich noch tun, um die Zeitüberschreitung der EF zu verhindern? Dies geschieht nur bei sehr großen Datenmengen. Mit kleinen Datensätzen funktioniert alles einwandfrei.

Hier ist einer der Fehler, die ich bekomme:

System.Data.EntityCommandExecutionException: Beim Ausführen der Befehlsdefinition ist ein Fehler aufgetreten. Einzelheiten finden Sie in der inneren Ausnahme. ---> System.Data.SqlClient.SqlException: Zeitüberschreitung abgelaufen. Die Zeitspanne, die vor Abschluss des Vorgangs verstrichen ist oder der Server nicht reagiert.


OK - ich habe das zum Laufen gebracht und es ist albern, was passiert ist. Ich hatte sowohl die Verbindungszeichenfolge mit Default Command Timeout=300000als auch das CommandTimeout auf 180 gesetzt. Als ich die Default Command Timeoutaus der Verbindungszeichenfolge entfernte, funktionierte es. Die Antwort besteht also darin, das CommandTimeout in Ihrem Repository für Ihr Kontextobjekt wie folgt manuell festzulegen:

this.context.CommandTimeout = 180;

Anscheinend hat das Festlegen der Timeout-Einstellungen in der Verbindungszeichenfolge keine Auswirkungen darauf.

Halcyon
quelle
Entfernen Sie & quot; von der Verbindungszeichenfolge
Brian Webster
Siehe
Saif Khan
5
@ hamlin11 In einer EF-Verbindungszeichenfolge muss definiert werden, welcher Teil eine Verbindungszeichenfolge und welcher Teil EF-Metadaten sind. Lassen Sie &quot;in der Zeichenkette.
Chev
2
Mein Vorschlag ist, bevor Sie das Timeout erhöhen, zuerst zu untersuchen, warum EF eine Zeitüberschreitung aufweist. In unserem Fall haben wir festgestellt, dass wir NONCLUSTEREDeinigen Tabellen Indizes hinzufügen müssen, wodurch das Timeout-Problem für uns behoben wurde.
Zulucoda
Ich arbeite mit dem MS-Support an einem SQL-Timeout-Problem. In diesem Fall wird die Datenbank in SQL Azure gehostet. Mir wurde mitgeteilt, dass für alle Azure PaaS-Dienste (PaaS-Websites und SQL Azure usw.) ein universelles Zeitlimit von 230 Sekunden besteht. Dies hat immer Vorrang, auch wenn Sie ein Zeitlimit manuell festlegen. Dies dient zum Schutz der Ressourcen einer mandantenfähigen PaaS-Infrastruktur.
Ian Robertson

Antworten:

551

Es ist ein Fehler beim Festlegen des Standardbefehlszeitlimits in der EF-Verbindungszeichenfolge bekannt.

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

Entfernen Sie den Wert aus der Verbindungszeichenfolge und legen Sie ihn für das Datenkontextobjekt selbst fest. Dies funktioniert, wenn Sie den widersprüchlichen Wert aus der Verbindungszeichenfolge entfernen.

Entity Framework Core 1.0:

this.context.Database.SetCommandTimeout(180);

Entity Framework 6:

this.context.Database.CommandTimeout = 180;

Entity Framework 5:

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

Entity Framework 4 und niedriger:

this.context.CommandTimeout = 180;
Chev
quelle
5
Wie kann ich dies mit edmx erreichen?
Iroel
2
In welcher Version von EntityFramework ist dies behoben? Ich kann den EF-Fehler dafür nicht finden.
Rudimenter
7
Ich glaube nicht, dass dies ein Fehler ist, sondern beabsichtigt, siehe Abschnitt Bemerkungen hier Link
Mick P
3
Da einige Einstellungen in ms sind und einige in s, ich sah es bis hier ist Command in Sekunden.
JabberwockyDecompiler
6
In Entity Framework 7 können Sie dies im Konstruktor von DbContext / IdentityDbContext festlegen:this.Database.SetCommandTimeout(180);
Thomas Hagström
101

Wenn Sie einen DbContext verwenden, verwenden Sie den folgenden Konstruktor, um das Befehlszeitlimit festzulegen:

public class MyContext : DbContext
{
    public MyContext ()
    {
        var adapter = (IObjectContextAdapter)this;
        var objectContext = adapter.ObjectContext;
        objectContext.CommandTimeout = 1 * 60; // value in seconds
    }
}
Saille
quelle
3
@ErickPetru, so dass Sie es leicht auf eine andere Anzahl von Minuten ändern können :), auch wäre ich nicht zu überrascht, wenn der Compiler diese Multiplikation optimiert!
Joel Verhagen
2
@ JoelVerhagen, sei nicht überrascht. Hier ist eine gute Erklärung, wann die automatische Optimierung stattfindet: stackoverflow.com/questions/160848/… . In diesem Fall nehme ich an, dass dies sogar passiert (da es sich um zwei wörtliche Werte handelt), aber ehrlich gesagt finde ich den Code auf diese Weise irgendwie seltsam.
Erick Petrucelli
33
meh ... Kinder hungern ... wen interessiert 1 * 60?
Timmerz
9
@ErikPetru, dies ist eigentlich eine sehr verbreitete Praxis und macht den Code besser lesbar.
Calvin
Was ist der beste Weg, um damit umzugehen, da meine DbContextabgeleitete Klasse automatisch aus einer edmxDatei generiert wurde ?
Matt Burland
41

Wenn Sie DbContextEF v6 + verwenden, können Sie alternativ Folgendes verwenden:

this.context.Database.CommandTimeout = 180;
Paul
quelle
13

Normalerweise erledige ich meine Operationen innerhalb einer Transaktion . Wie ich erfahren habe, reicht es nicht aus, das Zeitlimit für den Kontextbefehl festzulegen, aber die Transaktion benötigt einen Konstruktor mit einem Timeout-Parameter. Ich musste beide Timeout-Werte einstellen, damit es richtig funktioniert.

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

Am Ende der Funktion habe ich das Befehls-Timeout auf den vorherigen Wert in prevto zurückgesetzt.

Verwenden von EF6

Pillesoft
quelle
Überhaupt kein guter Ansatz. Früher habe ich viel Transaktionsumfang hinzugefügt und es wurde für mich zu einem Albtraum in einem Projekt. Ersetzte schließlich den gesamten Transaktionsbereich durch einen einzigen SAVEChanges () in EF 6+. Überprüfen Sie diese coderwall.com/p/jnniww/…
Monde
Diese Antwort sollte eine höhere Stimme haben. Ich habe alle Möglichkeiten ausprobiert, um das Zeitlimit zu erhöhen, aber nur, wenn ich sowohl das Zeitlimit für den Kontextbefehl als auch den Transaktionsbereich festgelegt habe, hat es funktioniert.
Gang
3

Ich weiß, dass dies ein sehr alter Thread ist, aber EF hat dies immer noch nicht behoben. Für Benutzer, die automatisch generiert werden, DbContextkann der Timeout mithilfe des folgenden Codes manuell festgelegt werden.

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;
    }
Shiva N.
quelle
3

Wenn Sie Entity Framework wie ich verwenden, sollten Sie Timeout für die Startup-Klasse wie folgt definieren:

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

Das habe ich finanziert. Vielleicht hilft es jemandem:

Auf geht's:

Wenn Sie LINQ mit EF verwenden und nach genauen Elementen suchen, die in der Liste wie folgt enthalten sind:

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

Alles läuft gut, bis IdList mehr als eine ID enthält.

Das Problem mit dem Zeitlimit tritt auf, wenn die Liste nur eine ID enthält. Um das Problem zu beheben, verwenden Sie die if-Bedingung, um die Anzahl der IDs in IdList zu überprüfen.

Beispiel:

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();
}

Erläuterung:

Versuchen Sie einfach, SQL Profiler zu verwenden, und überprüfen Sie die von Entity Frameeork generierte Select-Anweisung. …

tosjam
quelle