Мне очень нравится концепция IRecordAuthority, которую я видел для фильтрации записей, для которых разрешено запрашивать c идентификаторов в EF DbContext. Интерфейс объявляет Expression<Func<TEntity, bool>> Clause<TEntity>() where TEntity : IEntity
и реализован следующим образом:
public class AssignedUserRecordAuthority : IRecordAuthority
{
private readonly IUserService _userService;
public AssignedUserRecordAuthority(IUserService userService)
{
_userService = userService;
}
public Expression<Func<TEntity, bool>> Clause<TEntity>() where TEntity : IEntity
{
if (typeof(TEntity) == typeof(Customer))
{
var name = _userService.ClaimsIdentity.Name;
return x => (x as Customer).ManagedBy == name;
}
return x => false;
}
}
В моем EntityDbContext есть вызов, который вставляет это выражение в каждый запрос IQueryable из контекста:
public new IQueryable<TEntity> Get<TEntity>() where TEntity : class, IEntity
{
return Set<TEntity>()
.AsExpandable()
.Where(_recordAuthority.Clause<TEntity>());
}
Вызывающий Затем код может использовать стандартный Linq для данного варианта использования.
Проблема, с которой я столкнулся, заключается в следующем:
System.AggregateException: 'Произошла одна или несколько ошибок. (Выражение LINQ 'DbSet .Where (c => (c as Customer) .ManagedBy == __name_0)' не может быть переведено. Перепишите запрос в форме, которая может быть переведена, или переключитесь на оценку клиента явно путем вставки вызова к AsEnumerable (), AsAsyncEnumerable (), ToList () или ToListAsyn c (). См. https://go.microsoft.com/fwlink/?linkid=2101038 для получения дополнительной информации.) '
I можно только предположить, что EF пытается перевести приведение, для которого нет поставщика. Я был бы удивлен, если бы это было сравнение строк. Так как различные решения, которые я добавлю для каждого типа сущности, могут в значительной степени зависеть от доступа к свойствам каждой сущности для сравнения, может ли кто-нибудь увидеть, как я могу добавить этап приведения вне выражения, который не приведет к сбою перевода?
Целью реализаций recordauthority является создание набора условий, которые являются выражениями для определенных c классов сущностей, реализующих IEntity, для ограничения строк, которые вызывающий может видеть. Это выражение устанавливается до выражения вызывающего абонента и не может быть изменено вызывающим, поэтому обеспечивает безопасность на уровне строк, которую EF не обеспечивает из коробки. Этот класс вернет x => true внизу, поскольку для любых сущностей, к которым будут применяться ограничения, будет сделана проверка блока if для типа TEntity, а внутри этого будет построено соответствующее выражение. Приведение к указанному типу объекта c требуется в тех случаях, когда значения в таблице необходимо сравнивать с известными значениями, такими как имя пользователя, вошедшего в систему в моем примере, но это может быть что угодно.
ОБНОВЛЕНИЕ : Полный код с рабочим примером: https://github.com/steveski/Perigee.Framework