Solución:
Los tipos de consulta son solo lectura por definición (para todos proveedores de bases de datos, no solo en memoria):
- Nunca se realiza un seguimiento de los cambios en DbContext y, por lo tanto, nunca se insertan, actualizan o eliminan en la base de datos.
Sin embargo, además de sus escenarios de uso habituales de
- Asignación a vistas de la base de datos.
- Asignación a tablas que no tienen una clave principal definida.
ellos permiten
- Mapeo de consultas definidas en el modelo.
o en otras palabras
- Puede asignarse a un definición de consulta – Una consulta de definición es una consulta secundaria declarada en el modelo que actúa como fuente de datos para un tipo de consulta.
que se logra con la API fluida de ToQuery:
Configura una consulta que se utiliza para proporcionar datos para un tipo de consulta.
Entonces, para probar los tipos de consultas con la base de datos en memoria, debe utilizar el definición de consulta capacidad de mapeo.
Por ejemplo, adentro OnModelCreating
anular, podría agregar algo como esto:
if (Database.IsInMemory())
{
// In memory test query type mappings
modelBuilder.Query<MyQueryType>().ToQuery(() => LINQ_query);
// ... similar for other query types
}
else
{
// Database query type mappings
modelBuilder.Query<MyQueryType>().ToView("MyQueryTypeView");
// ...
}
dónde LINQ_query
es un contexto de acceso de consulta LINQ normal DbSet
arena DbQuery
sy proyectando a MyQueryType
.
Luego, la prueba alimentaría a las entidades involucradas con datos y las consultas usando DbQuery
s recuperará los datos de la consulta de definición.
Lo anterior debería ser la forma recomendada de probar vistas en la base de datos de la memoria.
Solo para completar, es posible alimentar directamente el DbQuery
s con datos (básicamente burlándose de ellos) creando algún tipo de repositorio de consultas, pero con la siguiente restricción: debe ser compartido (static
), porque actualmente EF Core no maneja correctamente los miembros del contexto de la base de datos (como lo hace el filtro de consulta global) aparte de DbSet<T>
y DbQuery<T>
.
Algo como esto:
public static class FakeQueryProvider
{
static Dictionary<Type, IQueryable> queries = new Dictionary<Type, IQueryable>();
public static void SetQuery<T>(IQueryable<T> query)
{
lock (queries)
queries[typeof(T)] = query;
}
public static IQueryable<T> GetQuery<T>()
{
lock (queries)
return queries.TryGetValue(typeof(T), out var query) ? (IQueryable<T>)query : Enumerable.Empty<T>().AsQueryable();
}
public static QueryTypeBuilder<T> ToFakeQuery<T>(this QueryTypeBuilder<T> builder)
where T : class
{
return builder.ToQuery(() => GetQuery<T>());
}
}
entonces en lugar de
.ToQuery(() => LINQ_query);
usarías
.ToFakeQuery();
y lo alimentaría dentro de la prueba así
List<MyQueryType> data = ...;
FakeQueryProvider.SetQuery(data.AsQueryable());
Aún así, recomiendo el primer enfoque debido a que el almacenamiento compartido limita la capacidad de ejecutar MyQueryType
pruebas relacionadas en paralelo.