Типы запросов доступны только для чтения по определению (для всех поставщиков баз данных, не только для памяти):
- Никогда не отслеживаются на предмет изменений в DbContext и, следовательно, никогда не вставляются, не обновляются и не удаляются в базе данных.
Однако, в дополнение к их обычным сценариям использования
- Отображение в представления базы данных.
- Отображение в таблицы, для которых не определен первичный ключ.
они позволяют
- Отображение на запросы, определенные в модели.
или другими словами
- Может быть сопоставлен с определяющим запросом - Определяющим запросом является вторичный запрос, объявленный в модели, который действует как источник данных для типа запроса.
, что достигается с помощью ToQuery свободный API:
Настраивает запрос, используемый для предоставления данных для типа запроса.
Таким образом, для тестирования типов запросов с использованием базы данных в памяти следует использовать определяющий запрос возможность сопоставления.
Например, внутри OnModelCreating
override вы можете добавить что-то вроде этого:
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");
// ...
}
, где LINQ_query
- это обычный запрос LINQ, обращающийся к контексту DbSet
с и DbQuery
с и проецирующий на MyQueryType
.
Затем тест передает данные соответствующим объектам, а запросы, использующие DbQuery
s, извлекают данные из определяющего запроса.
Вышеуказанный метод должен быть рекомендован для проверки представлений в базе данных памяти.
Просто для полноты можно напрямую снабжать данные DbQuery
данными (в основном имитируя их), создавая своего рода хранилище запросов, но со следующим ограничением - это должно быть shared (static
), поскольку в настоящее время EF Core неправильно обрабатывает элементы контекста БД (как это делает глобальный фильтр запросов), кроме DbSet<T>
и DbQuery<T>
.
Примерно так:
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>());
}
}
тогда вместо
.ToQuery(() => LINQ_query);
вы бы использовали
.ToFakeQuery();
и будет кормить его внутри теста вот так
List<MyQueryType> data = ...;
FakeQueryProvider.SetQuery(data.AsQueryable());
Тем не менее, я рекомендую первый подход, поскольку общее хранилище ограничивает возможность параллельного запуска MyQueryType
связанных тестов.