sql >> Base de Datos >  >> RDS >> Sqlserver

.NET Entity Framework y transacciones

Creando un Entity Framework global DbContext en una aplicación web es muy malo. El DbContext la clase no es segura para subprocesos (y lo mismo vale para ObjectContext de Entity Framework v1 clase). Se basa en el concepto de la unidad de trabajo y esto significa que lo usa para operar un solo caso de uso:por lo tanto, para una transacción comercial. Está destinado a manejar una sola solicitud.

La excepción que obtiene ocurre porque para cada solicitud crea una nueva transacción, pero intente usar ese mismo DbContext . Tienes suerte de que el DbContext detecta esto y lanza una excepción, porque ahora descubrió que esto no funcionará.

El DbContext contiene un caché local de entidades en su base de datos. Le permite hacer un montón de cambios y finalmente enviar esos cambios a la base de datos. Cuando se usa un solo DbContext estático , con múltiples usuarios llamando a SaveChanges en ese objeto, ¿cómo se supone que debe saber exactamente qué debe cometerse y qué no?

Como no lo sabe, guardará todo cambios, pero en ese momento es posible que otra solicitud aún esté realizando cambios. Cuando tenga suerte, EF o su base de datos fallarán porque las entidades se encuentran en un estado no válido. Si no tiene suerte, las entidades que se encuentran en un estado no válido se guardan con éxito en la base de datos y es posible que semanas después descubra que sus datos se corrompieron.

La solución a su problema es crear al menos un DbContext por solicitud . Si bien, en teoría, podría almacenar en caché un contexto de objeto en la sesión del usuario, también es una mala idea, porque en ese caso el DbContext normalmente durará demasiado y contendrá datos obsoletos (porque su memoria caché interna no se actualizará automáticamente).

También tenga en cuenta que tener un DbContext por subproceso es tan malo como tener una sola instancia para la aplicación web completa. ASP.NET utiliza un grupo de subprocesos, lo que significa que se creará una cantidad limitada de subprocesos durante la vida útil de una aplicación web. Básicamente, esto significa que esos DbContext en ese caso, las instancias seguirán vivas durante la vida útil de la aplicación, lo que provocará los mismos problemas con la obsolescencia de los datos.

Podrías pensar que tener un DbContext por subproceso en realidad es seguro para subprocesos, pero este no suele ser el caso, ya que ASP.NET tiene un modelo asincrónico que permite finalizar solicitudes en un subproceso diferente al que se inició (y las últimas versiones de MVC y Web API incluso permiten un número arbitrario de subprocesos manejan una sola solicitud en orden secuencial). Esto significa que el hilo que inició una solicitud y creó el ObjectContext puede estar disponible para procesar otra solicitud mucho antes de que finalice la solicitud inicial. Sin embargo, los objetos utilizados en esa solicitud (como una página web, un controlador o cualquier clase comercial) aún pueden hacer referencia a ese DbContext . Dado que la nueva solicitud web se ejecuta en ese mismo hilo, obtendrá el mismo DbContext instancia como lo que está usando la solicitud anterior. Esto nuevamente causa condiciones de carrera en su aplicación y causa los mismos problemas de seguridad de subprocesos que un DbContext global causas de la instancia.