我正在尝试实现向所有Entity Framework查询添加授权SQL过滤器的一般方法。 为此,我使用IDbCommandTreeInterceptor和DefaultExpressionVisitor。 模型是基本的:我们所有的实体都有一个RegionID,我们在Db上下文中有一个DynRegions实体集,其中包含用户可以访问的所有区域。
所以我想在下面的linq查询中动态添加Any过滤器(产生SQL SELECT EXISTS):
var query = context.Contacts
.Where(
c =>
context.DynRegions.Any(r => r.UserId == "150293818FC844F89AB36D044988F146" && r.RegionId == c.RegionId) &&
c.LastName.StartsWith("A"));
我已经开始使用此代码了:
public class RegionsInterceptor : IDbCommandTreeInterceptor
{
public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
{
if (interceptionContext.OriginalResult.DataSpace != DataSpace.SSpace) return;
var queryCommand = interceptionContext.Result as DbQueryCommandTree;
if (queryCommand == null) return;
var dbContext = interceptionContext.DbContexts.FirstOrDefault() as CrmContext;
if (dbContext == null) return;
var newQuery = queryCommand.Query.Accept(new RegionsQueryVisitor(dbContext));
interceptionContext.Result = new DbQueryCommandTree(
queryCommand.MetadataWorkspace,
queryCommand.DataSpace,
newQuery);
}
}
public class RegionsQueryVisitor : DefaultExpressionVisitor
{
private readonly CrmContext dbContext;
public RegionsQueryVisitor(CrmContext dbContext)
{
this.dbContext = dbContext;
}
public override DbExpression Visit(DbScanExpression expression)
{
var dbExpression = base.Visit(expression);
var currentExpressionBinding = DbExpressionBuilder.Bind(dbExpression);
var currentEntityRegionId = DbExpressionBuilder.Property(currentExpressionBinding.Variable, "RegionId");
var rolesExpression = expression.Target.EntityContainer.GetEntitySetByName("DynRole", true).Scan();
var rolesExpressionBinding = rolesExpression.Bind();
var rolesRegionIdProperty = DbExpressionBuilder.Property(rolesExpressionBinding.Variable, "RegionId");
var rolesUserIdProperty = DbExpressionBuilder.Property(rolesExpressionBinding.Variable, "UserId");
var userIdParameter = DbExpressionBuilder.Constant("150293818FC844F89AB36D044988F146");
var anyRolesExpression =
rolesExpression.Any(p =>
DbExpressionBuilder.Equal(rolesUserIdProperty, userIdParameter)
.And(
DbExpressionBuilder.Equal(rolesRegionIdProperty, currentEntityRegionId)));
var binding = expression.Bind();
return binding.Filter(anyRolesExpression);
}
}
我收到错误:引用的变量'Var_2'未在当前范围中定义。 错误发生在以下行:
interceptionContext.Result = new DbQueryCommandTree(
queryCommand.MetadataWorkspace,
queryCommand.DataSpace,
newQuery);
有什么想法吗?有没有人写过这样的拦截器/访客? 任何帮助/指针将不胜感激。
谢谢, 亚历