Estoy usando Entity Framework y ocasionalmente obtendré este error.
EntityCommandExecutionException
{"There is already an open DataReader associated with this Command which must be closed first."}
at System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands...
Aunque no estoy haciendo ninguna gestión de conexión manual.
Este error ocurre de forma intermitente.
código que desencadena el error (acortado para facilitar la lectura):
if (critera.FromDate > x) {
t= _tEntitites.T.Where(predicate).ToList();
}
else {
t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
}
usando el patrón Dispose para abrir una nueva conexión cada vez.
using (_tEntitites = new TEntities(GetEntityConnection())) {
if (critera.FromDate > x) {
t= _tEntitites.T.Where(predicate).ToList();
}
else {
t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
}
}
sigue siendo problemático
¿Por qué EF no reutilizaría una conexión si ya está abierta?
linq
entity-framework
sql-server-2008
Alma sónica
fuente
fuente
predicate
yhistoricPredicate
variables son. He descubierto que si pasasFunc<T, bool>
aWhere()
él se compilará y a veces funcionará (porque hace el "dónde" en la memoria). Lo que deberías estar haciendo es pasarExpression<Func<T, bool>>
aWhere()
.Respuestas:
No se trata de cerrar la conexión. EF gestiona la conexión correctamente. Comprendo que este problema es que hay múltiples comandos de recuperación de datos ejecutados en una sola conexión (o un solo comando con múltiples selecciones) mientras que el siguiente DataReader se ejecuta antes de que el primero haya completado la lectura. La única forma de evitar la excepción es permitir múltiples DataReaders anidados = activar MultipleActiveResultSets. Otro escenario cuando esto sucede siempre es cuando itera a través del resultado de la consulta (IQueryable) y activará una carga diferida para la entidad cargada dentro de la iteración.
fuente
Como alternativa al uso de MARS (MultipleActiveResultSets) puede escribir su código para no abrir múltiples conjuntos de resultados.
Lo que puede hacer es recuperar los datos en la memoria, de esa manera no tendrá el lector abierto. A menudo se debe a la iteración a través de un conjunto de resultados al intentar abrir otro conjunto de resultados.
Código de muestra:
Digamos que está haciendo una búsqueda en su base de datos que contiene estos:
Podemos hacer una solución simple a esto agregando .ToList () de esta manera:
Esto obliga al marco de la entidad a cargar la lista en la memoria, por lo tanto, cuando lo iteramos en el bucle foreach ya no está usando el lector de datos para abrir la lista, sino que está en la memoria.
Me doy cuenta de que esto podría no ser deseable si desea cargar algunas propiedades de forma diferida, por ejemplo. Este es principalmente un ejemplo que, con suerte, explica cómo / por qué podría tener este problema, para que pueda tomar decisiones en consecuencia
fuente
ToList
usa mil objetos, aumentará la memoria por tonelada. En este ejemplo específico, sería mejor combinar la consulta interna con la primera para que solo se genere una consulta en lugar de dos.Hay otra forma de superar este problema. Si es una mejor manera depende de su situación.
El problema resulta de la carga diferida, por lo que una forma de evitarlo es no tener una carga diferida, mediante el uso de Incluir:
Si usa los
Include
s apropiados , puede evitar habilitar MARS. Pero si pierde uno, obtendrá el error, por lo que habilitar MARS es probablemente la forma más fácil de solucionarlo.fuente
.Include
es una solución mucho mejor que habilitar MARS, y mucho más fácil que escribir su propio código de consulta SQL.Obtiene este error, cuando la colección que está intentando iterar es una carga lenta (IQueriable).
La conversión de la colección IQueriable en otra colección enumerable resolverá este problema. ejemplo
Nota: .ToList () crea un nuevo conjunto cada vez y puede causar problemas de rendimiento si se trata de datos de gran tamaño.
fuente
SELECT COUNT(*) FROM Users
= 5Resolví el problema fácilmente (pragmático) agregando la opción al constructor. Por lo tanto, lo uso solo cuando es necesario.
fuente
Intente en su cadena de conexión para establecer
MultipleActiveResultSets=true
. Esto permite la multitarea en la base de datos.Eso funciona para mí ... ya sea que su conexión en app.config o la configuró mediante programación ... espero que esto sea útil
fuente
Originalmente había decidido usar un campo estático en mi clase API para hacer referencia a una instancia del objeto MyDataContext (donde MyDataContext es un objeto de contexto EF5), pero eso es lo que parece crear el problema. Agregué código como el siguiente a cada uno de mis métodos API y eso solucionó el problema.
Como han dicho otras personas, los objetos de contexto de datos de EF NO son seguros para subprocesos. Por lo tanto, colocarlos en el objeto estático eventualmente causará el error "lector de datos" en las condiciones adecuadas.
Mi suposición original era que crear solo una instancia del objeto sería más eficiente y permitiría una mejor gestión de la memoria. Por lo que he reunido investigando este tema, ese no es el caso. De hecho, parece ser más eficiente tratar cada llamada a su API como un evento aislado y seguro para subprocesos. Asegurarse de que todos los recursos se liberen correctamente, ya que el objeto queda fuera de alcance.
Esto tiene sentido especialmente si lleva su API a la siguiente progresión natural, que sería exponerla como un WebService o REST API.
Divulgar
fuente
Noté que este error ocurre cuando envío un IQueriable a la vista y lo uso en un foreach doble, donde el foreach interno también necesita usar la conexión. Ejemplo simple (ViewBag.parents puede ser IQueriable o DbSet):
La solución simple es usar
.ToList()
en la colección antes de usarla. También tenga en cuenta que MARS no funciona con MySQL.fuente
ToList()
en mi primera llamada para obtener una colección de la base de datos. Luego hice unforeach
en esa lista y las llamadas posteriores funcionaron perfectamente en lugar de dar el error.Descubrí que tenía el mismo error, y ocurrió cuando estaba usando un en
Func<TEntity, bool>
lugar de unExpression<Func<TEntity, bool>>
para supredicate
.Una vez que cambié todo
Func's
aExpression's
la excepción, dejé de ser arrojado.Creo que
EntityFramwork
hace algunas cosas inteligentes conExpression's
las que simplemente no haceFunc's
fuente
(MyTParent model, Func<MyTChildren, bool> func)
modo para que mis ViewModels pudieran especificar una ciertawhere
cláusula para el método Generic DataContext. Nada funcionaba hasta que hice esto.2 soluciones para mitigar este problema:
.ToList()
después de su consulta, para que pueda iterar abriendo un nuevo DataReader..Include
(/ entidades adicionales que desea cargar en la consulta /) esto se llama carga ansiosa, que le permite (de hecho) incluir objetos asociados (entidades) durante la ejecución de una consulta con el DataReader.fuente
Un buen punto intermedio entre habilitar MARS y recuperar todo el conjunto de resultados en la memoria es recuperar solo ID en una consulta inicial y luego recorrer las ID que materializan cada entidad a medida que avanza.
Por ejemplo (usando las entidades de muestra "Blog y publicaciones" como en esta respuesta ):
Hacer esto significa que solo extrae unos pocos miles de enteros en la memoria, en lugar de miles de gráficos de objetos completos, lo que debería minimizar el uso de la memoria al tiempo que le permite trabajar elemento por elemento sin habilitar MARS.
Otro buen beneficio de esto, como se ve en la muestra, es que puede guardar los cambios a medida que recorre cada elemento, en lugar de tener que esperar hasta el final del ciclo (o alguna otra solución similar), como sería necesario incluso con MARS habilitado (ver aquí y aquí ).
fuente
context.SaveChanges();
inside loop :(. Esto no es bueno. Debe estar fuera del loop.En mi caso, descubrí que faltaban declaraciones de "espera" antes de las llamadas myContext.SaveChangesAsync (). Agregar esperar antes de esas llamadas asíncronas solucionó los problemas del lector de datos para mí.
fuente
Si intentamos agrupar parte de nuestras condiciones en un Func <> o método de extensión, obtendremos este error, supongamos que tenemos un código como este:
Esto arrojará la excepción si intentamos usarlo en un Where (), lo que deberíamos hacer en su lugar es construir un predicado como este:
Se puede leer más en: http://www.albahari.com/nutshell/predicatebuilder.aspx
fuente
Este problema se puede resolver simplemente convirtiendo los datos en una lista
fuente
En mi situación, el problema ocurrió debido a un registro de inyección de dependencia. Estaba inyectando un servicio de alcance por solicitud que estaba usando un dbcontext en un servicio registrado singleton. Por lo tanto, el dbcontext se utilizó dentro de múltiples solicitudes y, por lo tanto, el error.
fuente
En mi caso, el problema no tenía nada que ver con la cadena de conexión MARS sino con la serialización json. Después de actualizar mi proyecto de NetCore2 a 3, recibí este error.
Más información se puede encontrar aquí
fuente
Resolví este problema usando la siguiente sección de código antes de la segunda consulta:
puedes cambiar el tiempo de sueño en milisegundos
PD útil cuando se usan hilos
fuente