framework expired c# entity-framework-4 dbcontext command-timeout

execution timeout expired c# entity framework



Cómo configurar CommandTimeout para DbContext? (8)

Así es como resolví este problema cuando uso un archivo EDMX. Esta solución cambia la plantilla T4 predeterminada para hacer que la clase generada herede de una clase DbContext personalizada, que especifica un tiempo de espera de comando predeterminado, y una propiedad para cambiarla.

Estoy usando Visual Studio 2012 y EF 5.0. Tu experiencia puede diferir con otras versiones.

Crear una clase DbContext personalizada

public class CustomDbContext : DbContext { ObjectContext _objectContext; public CustomDbContext( string nameOrConnectionString ) : base( nameOrConnectionString ) { var adapter = (( IObjectContextAdapter) this); _objectContext = adapter.ObjectContext; if ( _objectContext == null ) { throw new Exception( "ObjectContext is null." ); } _objectContext.CommandTimeout = Settings.Default.DefaultCommandTimeoutSeconds; } public int? CommandTimeout { get { return _objectContext.CommandTimeout; } set { _objectContext.CommandTimeout = value; } } }

Esto tiene una función opcional: no estoy codificando el tiempo de espera del comando predeterminado. En cambio, lo estoy cargando desde la configuración del proyecto para poder cambiar el valor en un archivo de configuración. Cómo configurar y usar la configuración del proyecto no está en el alcance de esta respuesta.

Tampoco estoy forzando la codificación de la cadena de conexión o el nombre de la cadena de conexión. Ya pasó al constructor por la clase de contexto generado, por lo que no tiene sentido codificarlo aquí. Esto no es nada nuevo; el archivo EDMX ya genera el siguiente constructor para usted, por lo que solo estamos transfiriendo el valor.

public MyEntities() : base("name=MyEntities") { }

(Esto le indica a EF que cargue la cadena de conexión llamada "MyEntities" del archivo de configuración).

Estoy lanzando una excepción personalizada si ObjectContext alguna vez es nulo. No creo que lo sea nunca, pero es más significativo que obtener una NullReferenceException .

ObjectContext el ObjectContext en un campo para poder hacer una propiedad para acceder a él y anular el valor predeterminado.

Modificar la plantilla T4 del contexto de la entidad

En el Explorador de soluciones, expanda el archivo EDMX para que pueda ver las plantillas T4. Tienen una extensión .tt.

Haga doble clic en el archivo "MyModel.Context.tt" para abrirlo. Alrededor de la línea 57 deberías ver esto:

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext

Esta línea de plantilla genera la definición de clase de su clase "MyEntities", que hereda DbContext.

Cambie la línea para que la clase generada herede CustomDbContext, en su lugar:

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : CustomDbContext

Tan pronto como guarde este archivo, deberá regenerar la clase. De lo contrario, puede hacer clic con el botón derecho en el archivo EDMX y seleccionar "Ejecutar herramienta personalizada". Si expande el archivo "MyModel.Context.tt" debajo de su archivo EDMX, verá "MyModel.Context.cs". Ese es el archivo generado. Ábralo, y debería ver que ahora hereda CustomDbContext .

public partial class MyEntities : CustomDbContext

Eso es todo al respecto.

Cuestiones

Una vez que cambie la clase de contexto de DbContext a CustomDbContext , Visual Studio le dará un error si intenta agregar una nueva clase de controlador MVC utilizando la plantilla "Controlador con lectura / escritura de acciones y vistas, utilizando Entity Framework". Dirá "Tipo de contexto no admitido". Para evitar esto, abra la clase generada "MyModel.Context.cs" y cambie temporalmente el tipo hereda de nuevo a DbContext . Después de agregar su nuevo controlador, puede volver a CustomDbContext a CustomDbContext .

Estoy buscando una forma de configurar CommandTimeout para DbContext. Después de la búsqueda, encontré el camino al convertir DbContext en ObjectContext y el valor de configuración para la propiedad CommandTimeout de objectContext.

var objectContext = (this.DbContext as IObjectContextAdapter).ObjectContext;

Pero tengo que trabajar con DbContext.


Esto puede ayudarte.

public class MyContext : DbContext { public MyContext () : base(ContextHelper.CreateConnection("my connection string"), true) { ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300; } }


Funcionará con tu método.

O la subclase (del foro msdn )

public class YourContext : DbContext { public YourContext() : base("YourConnectionString") { // Get the ObjectContext related to this DbContext var objectContext = (this as IObjectContextAdapter).ObjectContext; // Sets the command timeout for all the commands objectContext.CommandTimeout = 120; } }


Me gusta el enfoque de extensión:

public static class DbContextExtensions { public static void SetCommandTimeout(this ObjectContext dbContext, int TimeOut) { dbContext.CommandTimeout = TimeOut; } }

y luego simplemente

((IObjectContextAdapter)cx).ObjectContext.SetCommandTimeout(300);


Me parece que cambiar el archivo .tt funciona para mí, ya que no pierdo el cambio más adelante:

Agregue esta línea:

((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300;

Justo después del creador de DbContext y antes del constructo! Loader.IsLazy:

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext { public <#=code.Escape(container)#>() : base("name=<#=container.Name#>") { ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300; <# if (!loader.IsLazyLoadingEnabled(container))

Debería aparecer en su Context.cs generado:

public MyEntities() : base("name=MyEntities") { ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 300; }


Si puede ayudar, esta es la solución VB.Net:

Dim objectContext As Objects.ObjectContext = CType(Me,IObjectContextAdapter).ObjectContext objectContext.commandTimeout = connectionTimeout


Vine aquí buscando un ejemplo de configuración del tiempo de espera para un solo comando en lugar de una configuración global.

Me imagino que probablemente ayude a alguien a tener un ejemplo de cómo lo logré:

var sqlCmd = new SqlCommand(sql, context.Database.Connection as SqlConnection); sqlCmd.Parameters.Add(idParam); sqlCmd.CommandTimeout = 90; if (sqlCmd.Connection.State == System.Data.ConnectionState.Closed) { sqlCmd.Connection.Open(); } sqlCmd.ExecuteNonQuery(); sqlCmd.Connection.Close();


var ctx = new DbContext(); ctx.Database.CommandTimeout = 120;