Tiempos de espera del marco de entidades

324

Estoy obteniendo tiempos de espera usando Entity Framework (EF) cuando uso una función de importación que demora más de 30 segundos en completarse. Intenté lo siguiente y no he podido resolver este problema:

He añadido Default Command Timeout=300000a la cadena de conexión en el app.config archivo en el proyecto que tiene el archivo EDMX como se sugiere aquí .

Así es como se ve mi cadena de conexión:

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

Intenté configurar CommandTimeout en mi repositorio directamente así:

private TrekEntities context = new TrekEntities();

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

¿Qué más puedo hacer para que el EF se agote? Esto solo sucede para conjuntos de datos muy grandes. Todo funciona bien con pequeños conjuntos de datos.

Aquí está uno de los errores que obtengo:

System.Data.EntityCommandExecutionException: se produjo un error al ejecutar la definición del comando. Vea la excepción interna para más detalles. ---> System.Data.SqlClient.SqlException: expiró el tiempo de espera. El tiempo de espera transcurrido antes de la finalización de la operación o el servidor no responde.


OK, tengo esto funcionando y es tonto lo que pasó. Tenía tanto la cadena de conexión con Default Command Timeout=300000CommandTimeout configurada en 180. Cuando eliminé Default Command Timeoutla cadena de conexión, funcionó. Entonces, la respuesta es configurar manualmente CommandTimeout en su repositorio en su objeto de contexto de la siguiente manera:

this.context.CommandTimeout = 180;

Aparentemente, la configuración del tiempo de espera en la cadena de conexión no tiene ningún efecto.

Martín pescador
fuente
Eliminar & quot; desde la cadena de conexión
Brian Webster
55
@ hamlin11 En una cadena de conexión EF, eso es necesario para definir qué parte es una cadena de conexión y qué parte son metadatos EF. Deja &quot;en la cuerda.
Chev
2
mi sugerencia es antes de aumentar el tiempo de espera para investigar primero para ver por qué EF está agotando el tiempo de espera. En nuestro caso, nos dimos cuenta de que necesitábamos agregar NONCLUSTEREDíndices a algunas de las tablas, esto resolvió el problema del tiempo de espera para nosotros.
zulucoda
Estoy trabajando con el soporte de MS en un problema de tiempo de espera de SQL: esto es cuando la base de datos está alojada en SQL Azure. Me dijeron que todos los servicios de Azure PaaS (sitios web de PaaS y SQL Azure, etc.) tienen un tiempo de espera universal de 230 segundos, y esto siempre tiene prioridad, incluso si configura un tiempo de espera manualmente. Esto es para proteger los recursos de la infraestructura PaaS multiempresa.
Ian Robertson

Respuestas:

552

Existe un error conocido al especificar el tiempo de espera predeterminado del comando dentro de la cadena de conexión EF.

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

Elimine el valor de la cadena de conexión y configúrelo en el objeto de contexto de datos. Esto funcionará si elimina el valor en conflicto de la cadena de conexión.

Entity Framework Core 1.0:

this.context.Database.SetCommandTimeout(180);

Entidad Marco 6:

this.context.Database.CommandTimeout = 180;

Entidad Marco 5:

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

Entity Framework 4 y siguientes:

this.context.CommandTimeout = 180;
Chev
fuente
55
¿Cómo puedo lograr esto usando edmx?
Iroel
2
¿En qué versión de EntityFramework se soluciona esto? No puedo encontrar el error de EF para ello.
rudimenter
77
No creo que esto sea un error, sino más bien por diseño, vea la sección Comentarios aquí enlace
Mick P
3
Debido a que algunas configuraciones están en ms y otras en s, lo busqué aquí , CommandTimeout está en segundos.
JabberwockyDecompiler
66
En Entity Framework 7 puede configurar esto en el constructor de DbContext / IdentityDbContext:this.Database.SetCommandTimeout(180);
Thomas Hagström
101

Si está utilizando un DbContext, use el siguiente constructor para configurar el tiempo de espera del comando:

public class MyContext : DbContext
{
    public MyContext ()
    {
        var adapter = (IObjectContextAdapter)this;
        var objectContext = adapter.ObjectContext;
        objectContext.CommandTimeout = 1 * 60; // value in seconds
    }
}
saille
fuente
3
@ErickPetru, para que pueda cambiarlo fácilmente a un número diferente de minutos :), ¡tampoco me sorprendería demasiado si el compilador optimiza esa multiplicación!
Joel Verhagen
2
@JoelVerhagen, no te sorprendas. Aquí hay una buena explicación de cuándo ocurre la optimización automática: stackoverflow.com/questions/160848/… . En este caso, supongo que incluso suceden (ya que son dos valores literales), pero sinceramente, creo que el código es un poco extraño de esta manera.
Erick Petrucelli
33
meh ... los niños se mueren de hambre ... ¿a quién le importa 1 * 60?
Timmerz
99
@ErikPetru, esta es una práctica muy común y hace que el código sea más legible.
Calvin
¿Cuál es la mejor manera de manejar esto dado que mi DbContextclase derivada se generó automáticamente a partir de un edmxarchivo?
Matt Burland
41

Si está utilizando DbContexty EF v6 +, alternativamente puede usar:

this.context.Database.CommandTimeout = 180;
Pablo
fuente
13

Usualmente manejo mis operaciones dentro de una transacción . Como he experimentado, no es suficiente establecer el tiempo de espera del comando de contexto, pero la transacción necesita un constructor con un parámetro de tiempo de espera. Tuve que establecer ambos valores de tiempo de espera para que funcione correctamente.

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

Al final de la función, retrasé el tiempo de espera del comando al valor anterior en anterior.

Usando EF6

Pillesoft
fuente
No es un buen enfoque en absoluto. Solía ​​agregar mucho alcance de transacción y se convirtió en una pesadilla para mí en un proyecto. Eventualmente reemplazó todo el alcance de la transacción con un solo SAVEChanges () en EF 6+. Mira esto coderwall.com/p/jnniww/…
Lunas
Esta respuesta debería tener mayor voto. Intenté todas las formas diferentes de aumentar el tiempo de espera, pero solo cuando configuré AMBOS tiempos de espera del comando de contexto y el alcance de la transacción funcionó.
Pandilla
3

Sé que este es un hilo muy antiguo en ejecución, pero EF aún no lo ha solucionado. Para las personas que usan autogenerado DbContextpueden usar el siguiente código para configurar el tiempo de espera manualmente.

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
fuente
3

Si está utilizando Entity Framework como yo, debe definir el tiempo de espera en la clase de inicio de la siguiente manera:

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

Esto es lo que he financiado. Tal vez ayude a alguien:

Así que, aquí vamos:

Si usa LINQ con EF buscando algunos elementos exactos contenidos en la lista como este:

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

todo va bien hasta que IdList contenga más de un Id.

El problema de "tiempo de espera" aparece si la lista contiene solo un Id. Para resolver el problema, use la condición if para verificar el número de identificadores en IdList.

Ejemplo:

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

Explicación:

Simplemente intente usar Sql Profiler y verifique la instrucción Select generada por Entity frameeork. ...

tosjam
fuente