stored framework first context code async c# .net entity-framework asynchronous using

first - using entity framework c#



Entity Framework, DBContext y using()+async? (5)

Buscaría el método ''one DbContext por solicitud'' y reutilizaría el DbContext dentro de la solicitud. Como todas las tareas deben completarse al final de la solicitud, puede deshacerse de ella de manera segura.

Ver ie: Un DbContext por solicitud en ASP.NET MVC (sin contenedor IOC)

Algunas otras ventajas:

  • algunas entidades ya pueden estar materializadas en el DbContext de consultas anteriores, guardando algunas consultas adicionales.
  • no tienes todos esos extra using declaraciones que abarrotan tu código.

Hay algo que me ha estado molestando durante mucho tiempo sobre Entity Framework.

El año pasado escribí una gran aplicación para un cliente que usa EF. Y durante el desarrollo todo funcionó muy bien.

Enviamos el sistema en agosto. Pero después de algunas semanas comencé a ver extrañas filtraciones de memoria en el servidor de producción. Mi proceso ASP.NET MVC 4 estaba ocupando todos los recursos de la máquina después de un par de días de funcionamiento (8 GB). Esto no fue bueno Busco en la red y vi que debe rodear todas las consultas y operaciones de EF en un bloque using() para poder eliminar el contexto.

En un día refactoré todo mi código para utilizarlo using() y esto resolvió mis problemas, ya que el proceso se basa en un uso constante de la memoria.

La razón por la que no envolví mis consultas en primer lugar, sin embargo, es que comencé mis primeros controladores y repositorios de los propios andamios de Microsofts incluidos en Visual Studio, estos no rodeaban sus consultas con el uso, sino que tenían el DbContext como una variable de instancia del controlador mismo.

Antes que nada : si es realmente importante deshacerse del contexto (algo que no sería raro, la dbconnection debe cerrarse, etc.), ¡Microsoft debería tener esto en todos sus ejemplos!

Ahora, he comenzado a trabajar en un nuevo gran proyecto con todos mis conocimientos en la cabeza y he estado probando las nuevas características de .NET 4.5 y EF 6 async y await . EF 6.0 tiene todos estos métodos asíncronos (por ejemplo, ToListAsync , ToListAsync , etc.).

public Task<tblLanguage> Post(tblLanguage language) { using (var langRepo = new TblLanguageRepository(new Entities())) { return langRepo.Add(RequestOrganizationTypeEnum, language); } }

En la clase TblLanguageRepo :

public async Task<tblLanguage> Add(OrganizationTypeEnum requestOrganizationTypeEnum, tblLanguage language) { ... await Context.SaveChangesAsync(); return langaugeDb; }

Sin embargo, cuando ahora rodeo mis declaraciones en un bloque using() obtengo la excepción, DbContext was disposed , antes de que la consulta haya podido regresar. Este es el comportamiento esperado. La consulta se ejecuta de manera asíncrona y el bloque de using finaliza antes de la consulta. Pero, ¿cómo debo deshacerme de mi contexto de forma adecuada mientras uso la función asíncrona y espero las funciones de ef 6?

Por favor, apúntame en la dirección correcta.

¿Se using() en EF 6? ¿Por qué los ejemplos de Microsoft nunca cuentan con eso? ¿Cómo se utilizan las características de sincronización y se elimina el contexto de forma adecuada?


En mi humilde opinión, de nuevo es un problema causado por el uso de lazy-loading. Después de disponer de su contexto, ya no puede cargar una propiedad de forma diferida porque la eliminación del contexto cierra la conexión subyacente al servidor de la base de datos.

Si tiene activada la carga diferida y la excepción se produce después del ámbito de using , consulte https://.com/a/21406579/870604


Estoy de acuerdo con @Dirk Boer en que la mejor manera de administrar la duración de DbContext es con un contenedor IoC que elimine el contexto cuando se complete la solicitud http. Sin embargo, si eso no es una opción, también podría hacer algo como esto:

var dbContext = new MyDbContext(); var results = await dbContext.Set<MyEntity>.ToArrayAsync(); dbContext.Dispose();

El enunciado using es solo azúcar sintáctico para deshacerse de un objeto al final de un bloque de código. Puede lograr el mismo efecto sin un bloque de using simplemente llamando. .Dispose usted mismo.

Ahora que lo pienso, no deberías obtener excepciones de disposición de objetos si usas la palabra clave await dentro del bloque de uso:

public async Task<tblLanguage> Post(tblLanguage language) { using (var langRepo = new TblLanguageRepository(new Entities())) { var returnValue = langRepo.Add(RequestOrganizationTypeEnum, language); await langRepo.SaveChangesAsync(); return returnValue; } }


Si está utilizando patrones de programación de n niveles adecuados, su controlador nunca debe saber que se está realizando una solicitud de base de datos. Eso debería suceder en su capa de servicio.

Hay un par de maneras de hacer esto. Una es crear 2 constructores por clase, uno que cree un contexto y otro que acepte un contexto ya existente. De esta forma, puede pasar el contexto si ya se encuentra en la capa de servicio, o crear uno nuevo si es el controlador / modelo que llama a la capa de servicio.

El otro es crear una sobrecarga interna de cada método y aceptar el contexto allí.

Pero, sí, deberías envolver estos en un uso.

En teoría, la recolección de basura DEBERÍA limpiarlos sin envolverlos, pero no confío completamente en el GC.


Tu codigo:

public Task<tblLanguage> Post(tblLanguage language) { using (var langRepo = new TblLanguageRepository(new Entities())) { return langRepo.Add(RequestOrganizationTypeEnum, language); } }

está eliminando el repositorio antes de devolver una Task . Si haces el código async :

public async Task<tblLanguage> Post(tblLanguage language) { using (var langRepo = new TblLanguageRepository(new Entities())) { return await langRepo.Add(RequestOrganizationTypeEnum, language); } }

luego dispondrá el repositorio justo antes de que la Task complete. Lo que realmente ocurre es que cuando tocas el await , el método devuelve una Task incompleta (ten en cuenta que el bloque que está using todavía está "activo" en este punto). Luego, cuando la tarea langRepo.Add completa, el método Post reanuda la ejecución y elimina langRepo . Cuando se completa el método Post , se completa la Task devuelta.

Para obtener más información, vea mi introducción async .