Мне нужно динамически фильтровать данные из конкретной таблицы в зависимости от прав пользователя.Например, «обычный» пользователь может видеть только назначенные ему записи, а администратор может видеть все.Я использую ninject для создания контекста БД для каждого запроса и создания контекста, передавая дополнительную информацию о пользователе в конструктор.Затем я применяю динамическую фильтрацию (EF6) из расширений EntityFramework-Plus:
public MyDbContext(bool isAdmin, string userId) : this()
{
if (!isAdmin)
{
this.Filter<MyTable>(table => table.Where(...));
}
}
Это решение работает, как и ожидалось, то есть вызывает такие методы, как:
ctx.MyTable.Where(...)
Результатом является дополнительное объединение, объявленное в фильтре.
Но странно себя ведет, когда я использую метод Find ().Я использую профилировщик SqlServer, чтобы увидеть, что происходит внутри:
- Я создаю контекст как ограниченный (не администратор) - вызов Find () приведет к дополнительному оператору WHERE, соответствующему лямбда-выражению фильтра
- Затем я создаю контекст как администратор (отдельный запрос) - вызов Find () приведет к тому же самому выражению SQL (я не ожидаю никаких дополнительных предложений SQL).
AFAIK это как-то связано с кэшированием запросов, так как добавление дополнительной строки в конструктор, похоже, решает проблему:
public MyDbContext(bool isAdmin, string userId) : this()
{
// this "solves" the problem
QueryFilterManager.ClearQueryCache(this);
if (!isAdmin)
{
this.Filter<MyTable>(table => table.Where(...));
}
}
Это выглядит как большое перерасход, и это не такприблизь меня к пониманию проблемы.Итак, вот мои вопросы:
- Почему эта проблема не влияет на Where (), но влияет на Find ()?
- Есть ли более чистый способ решения этой проблемы?Я читал о библиотеке динамических фильтров, но она мне не подходит, так как она работает только в модели с первым кодом (сначала БД здесь).
- Существуют ли более эффективные концепции фильтрации данных на основе данных по запросу (например, userId)в моем примере)?
ОБНОВЛЕНИЕ
Вот как выглядит мое лямбда-выражение:
private Func<IQueryable<MyTable>, IQueryable<MyTable>> GetFilter(string userId)
{
return t => t
.Where(c.DataScopes.Any(
x => x.AspNetGroups.Any(
ang => ang.AspNetUsers.Any(
anu => anu.Id == userId))));
}
AspNetGroups - моя пользовательская таблица для группировки пользователей.Данные разрешения назначаются группе пользователей.