.net vb.net entity-framework entity-framework-5 entity-framework-4.3.1

.net - EF 4.3.1 y EF 5.0 DbSet.Local es más lento que una consulta de base de datos real



vb.net entity-framework (3)

¿Por qué no simplemente guarda la Lista de cadenas de la primera consulta y la utiliza en su lugar?

List<string> cities = db.Cities.Select( x=>x.CityName).ToList();

Local puede ser más lento debido a Select, que podría estar haciendo algunas verificaciones de consistencia.

Tengo una base de datos con una tabla de aproximadamente 16,500 ciudades y un modelo de datos EF (Database-First) para esa base de datos. Los precargo en la memoria con el código:

Db.Cities.Load()

... luego, cuando es hora de usarlos, he intentado cada una de las siguientes consultas:

Dim cities() As String = Db.Cities.Select(Function(c) c.CityName).ToArray Dim cities() As String = Db.Cities.Local.Select(Function(c) c.CityName).ToArray

La primera consulta es rápida (~ 10ms), pero la segunda tarda aproximadamente 2,3 segundos en ejecutarse la primera vez (aunque es más rápida que la primera consulta cuando se llama después de eso).

Esto no tiene sentido porque el Analizador de SQL Server verifica que la primera consulta está llegando a la base de datos en otra máquina, ¡pero la segunda no!

He intentado desactivar Db.Configuration.AutoDetectChangesEnabled y he intentado generar previamente las vistas.

¿Qué puedo hacer para hacer .Local más rápido? (No todos los clientes que ejecuten esta aplicación estarán en una LAN rápida).


El siguiente método de extensión devolverá un IEnumerable<T> contiene las entidades locales almacenadas en caché del DbSet sin la sobrecarga de inicio incurrida por el método DbSet.Local() que detecta cambios de contexto y crea un objeto ObservableCollection<T> .

<Extension()> Public Function QuickLocal(Of T As Class)(ByRef DbCollection As DbSet(Of T)) As IEnumerable(Of T) Dim baseType = DbCollection.[GetType]().GetGenericArguments(0) Dim internalSet = DbCollection.GetType().GetField("_internalSet", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance).GetValue(DbCollection) Dim internalContext = internalSet.GetType().GetProperty("InternalContext").GetValue(internalSet, Nothing) Return DirectCast(internalContext.GetType.GetMethod("GetLocalEntities").MakeGenericMethod(baseType).Invoke(internalContext, Nothing), IEnumerable(Of T)) End Function

Llamar a .QuickLocal en un DbSet que contiene 19,679 entidades toma 9 ms, mientras que llamar a .Local toma 2121 ms en la primera llamada.


Recorrí la fuente de la propiedad Local usando la característica práctica de Resharper. Primero verá una llamada a DetectChanges que probablemente no sea su problema si todo lo que está ejecutando son las tres líneas anteriores. Pero luego EF crea una nueva colección Observable para Local y la llena artículo por artículo. Cualquiera de los dos puede ser costoso en la primera llamada.

La consulta directamente contra el DbSet se DbSet a los proveedores de la base de datos de EF que estoy seguro que acceden directamente al caché local interno.