Timeout del framework delle entità


324

Ricevo timeout utilizzando Entity Framework (EF) quando si utilizza un'importazione di funzione che richiede più di 30 secondi per essere completata. Ho provato quanto segue e non sono stato in grado di risolvere questo problema:

Ho aggiunto Default Command Timeout=300000alla stringa di connessione nel file App.Config nel progetto che ha il file EDMX come suggerito qui .

Ecco come appare la mia stringa di connessione:

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

Ho provato a impostare CommandTimeout nel mio repository direttamente in questo modo:

private TrekEntities context = new TrekEntities();

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

Cos'altro posso fare per evitare il timeout dell'EF? Questo accade solo per set di dati molto grandi. Tutto funziona bene con piccoli set di dati.

Ecco uno degli errori che sto riscontrando:

System.Data.EntityCommandExecutionException: si è verificato un errore durante l'esecuzione della definizione del comando. Vedere l'eccezione interna per i dettagli. ---> System.Data.SqlClient.SqlException: Timeout scaduto. Il periodo di timeout è trascorso prima del completamento dell'operazione o il server non risponde.


OK - Ho funzionato ed è sciocco quello che è successo. Avevo Default Command Timeout=300000impostato sia la stringa di connessione che CommandTimeout su 180. Quando ho rimosso la Default Command Timeoutstringa di connessione, ha funzionato. Quindi la risposta è impostare manualmente CommandTimeout nel repository sull'oggetto contestuale in questo modo:

this.context.CommandTimeout = 180;

Apparentemente l'impostazione delle impostazioni di timeout nella stringa di connessione non ha alcun effetto su di essa.


Rimuovi & quot; dalla stringa di connessione
Brian Webster,


5
@ hamlin11 In una stringa di connessione EF, è necessario definire quale parte è la stringa di connessione e quale parte sono i metadati EF. Lascia &quot;nella stringa.
Chev,

2
il mio suggerimento è prima di aumentare il timeout da investigare prima per capire perché EF sta scadendo. Nel nostro caso ci siamo resi conto che dovevamo aggiungere NONCLUSTEREDindici ad alcune tabelle, questo ha risolto il problema del timeout per noi.
Zulucoda,

Sto lavorando con il supporto MS su un problema di timeout SQL: questo è quando il DB è ospitato in SQL Azure. Mi è stato detto che in tutti i servizi PaaS di Azure (siti Web PaaS e SQL Azure ecc.) Esiste un timeout universale di 230 secondi e questo ha sempre la precedenza, anche se si imposta manualmente un timeout. Questo per proteggere le risorse dell'infrastruttura PaaS multi-tenant.
Ian Robertson,

Risposte:


552

Esiste un bug noto con la specifica del timeout del comando predefinito nella stringa di connessione EF.

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

Rimuovere il valore dalla stringa di connessione e impostarlo sull'oggetto del contesto dati stesso. Ciò funzionerà se si rimuove il valore in conflitto dalla stringa di connessione.

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 e precedenti:

this.context.CommandTimeout = 180;

5
Come posso ottenere questo risultato utilizzando edmx?
iroel,

2
In quale versione di EntityFramework è stato risolto? Non riesco a trovare il bug EF per questo.
rudimenter

7
Non credo che questo sia un bug, ma piuttosto in base alla progettazione, vedere la sezione Note qui link
Mick P

3
Poiché alcune impostazioni sono in ms e alcune in s, l'ho cercato qui , CommandTimeout è in pochi secondi.
JabberwockyDecompiler

6
In Entity Framework 7 puoi impostarlo nel costruttore di DbContext / IdentityDbContext:this.Database.SetCommandTimeout(180);
Thomas Hagström,

101

Se si utilizza un DbContext, utilizzare il costruttore seguente per impostare il timeout del comando:

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

3
@ErickPetru, quindi puoi facilmente cambiarlo in un diverso numero di minuti :), inoltre non sarei troppo sorpreso se il compilatore ottimizzasse quella moltiplicazione!
Joel Verhagen,

2
@JoelVerhagen, non essere sorpreso. Ecco una buona spiegazione di quando si verifica l'ottimizzazione automatica: stackoverflow.com/questions/160848/… . In questo caso, suppongo che ciò accada (dato che sono due valori letterali), ma onestamente penso che il codice sia strano in questo modo.
Erick Petrucelli,

33
meh ... i bambini muoiono di fame ... a chi importa circa 1 * 60?
Timmerz,

9
@ErikPetru, questa è in realtà una pratica molto comune e rende il codice più leggibile.
Calvin,

Qual è il modo migliore per gestire questo dato che la mia DbContextclasse derivata è stata generata automaticamente da un edmxfile?
Matt Burland,

41

Se si utilizza DbContextEF v6 +, in alternativa è possibile utilizzare:

this.context.Database.CommandTimeout = 180;

13

Di solito gestisco le mie operazioni all'interno di una transazione . Come ho sperimentato, non è sufficiente impostare il timeout del comando di contesto, ma la transazione richiede un costruttore con un parametro di timeout. Ho dovuto impostare entrambi i valori di timeout affinché funzionasse correttamente.

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

Alla fine della funzione ho ripristinato il timeout del comando al valore precedente in prevto.

Utilizzando EF6


Non è affatto un buon approccio. Aggiungevo molto ambito di transazione e per me è diventato un incubo in un progetto. Alla fine ha sostituito tutto l'ambito della transazione con un singolo SAVEChanges () in EF 6+. Controlla questo coderwall.com/p/jnniww/…
Lune

Questa risposta dovrebbe avere un voto più elevato. Ho provato tutti i modi diversi per aumentare il timeout ma solo quando ho impostato ENTRAMBI timeout del comando di contesto e ambito Transaction, ha funzionato.
Gang

3

So che questo thread è in esecuzione molto vecchio, ma EF non ha ancora risolto questo problema. Per le persone che utilizzano la generazione automatica è DbContextpossibile utilizzare il codice seguente per impostare manualmente il timeout.

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

Se si utilizza Entity Framework come me, è necessario definire il timeout nella classe Startup come segue:

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

1

Questo è ciò che ho finanziato. Forse aiuterà qualcuno:

Quindi eccoci qui:

Se usi LINQ con EF alla ricerca di alcuni elementi esatti contenuti nell'elenco come questo:

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

tutto sta andando bene fino a quando IdList contiene più di un ID.

Il problema del "timeout" viene visualizzato se l'elenco contiene solo un ID. Per risolvere il problema, utilizzare if condition per controllare il numero di ID in IdList.

Esempio:

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

Spiegazione:

Prova semplicemente a utilizzare Sql Profiler e controlla l'istruzione Select generata da Entity frameeork. ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.