我正在编写一个类似于角色的系统;用户只能看到他们有权访问的数据 . 这适用于用于表单填充,搜索,列表,报告等的数据 .
我计划通过在执行之前向EF查询添加“WHERE”子句来实现为添加请求添加过滤器的方式 .
如果不是因为我们使用泛型这一事实,这将是简单的 .
Get函数曾经是这个
public class EntityFactory<TEntity, TDto> : IEntityFactory<TEntity, TDto> where TEntity : class
{
private readonly DBContext _context;
private readonly IMapper _mapper;
private DbSet<TEntity> _dbset;
public EntityFactory(DBContext context, IMapper mapper)
{
//...
}
public async Task<List<TDto>> GetAsync()
{
List<TEntity> d = await _dbset.AsNoTracking().ToListAsync();
return _mapper.Map<List<TDto>>(d);
}
}
我想做什么:
public async Task<List<TDto>> GetAsync()
{
//If the object implements a special interface
if (i.GetInterfaces().Contains(typeof(IFoo)))
{
//expression to filter the data on a linked table containing the user's Id.
Expression<Func<Bar, bool>> exp = x => x.Foos.Any(a => a.UserId == _user.UserId);
//add the expression to the dbSet
_dbSet = _dbSet.Where(exp);
}
//Execute the get
List<TEntity> d = await q.AsNoTracking().ToListAsync();
//return the converted objects
return _mapper.Map<List<TDto>>(d);
}
但这不起作用!我得到这个编译器错误:
Argument 2: cannot convert from 'System.Linq.Expressions.Expression<System.Func<Bar, bool>>' to 'System.Linq.Expressions.Expression<System.Func<TEntity, int, bool>>'
有没有办法:
-
创建未检查的"dynamic"查询或
-
将dbset更改为所需类型,应用表达式并将其返回到泛型类型?
2 回答
您可以使用Linq动态查询来应用where子句 .
通过寻找不同的方式来查看此问题可能会更好 . 由于这是一个安全过滤器,您可能会发现意外地没有实现IFoo,并且您没有按照自己的想法进行过滤 .
话虽这么说,你可以做到这一点,但它需要几个步骤 . 您可以手动构建表达式,但我更喜欢在代码中构建表达式,然后使用ReplaceVisitor修改当前类型的表达式 .
首先,我创建一个类型为
Expression<Func<IFoo,bool>>
的过滤表达式 . 这不是最终的过滤表达式,但它是兼容的,因为我们正在检查泛型类型是否实现了IFoo .接下来,我使用Expression Visitor将每个对IFoo参数表达式的引用替换为TEntity参数表达式 . 结果表达式将是一个
Expresssion<Func<TEntity,bool>>
,所以我把它转换为,所以编译器会很高兴 .最后,我将结果表达式传递给Where子句 .
注意:这是一个非异步版本,但它演示了这些原则 .