如何在EF中构造重叠DbExpression

时间:2017-10-31 11:46:55

标签: c# entity-framework linq

我需要创建一个'Car/Featured' ,它将在自定义DbExpression中用于过滤用户(用户的客户端集合必须至少包含其他列表中的项目)。

基本上我需要转换这个Linq语句:

IDbCommandTreeInterceptor

我该怎么做?

1 个答案:

答案 0 :(得分:1)

你可以像这样构建这样的拦截器:

public class Interceptor : IDbCommandTreeInterceptor {
    private readonly int[] _clientIds;
    public Interceptor(int[] clientIds) {
        _clientIds = clientIds;
    }
    public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext) {            
        if (interceptionContext.Result.CommandTreeKind == DbCommandTreeKind.Query)
            InterceptQuery(interceptionContext);
    }

    private void InterceptQuery(DbCommandTreeInterceptionContext interceptionContext) {
        if (interceptionContext.Result.DataSpace != DataSpace.CSpace)
            return;

        var query = interceptionContext.Result as DbQueryCommandTree;
        if (query != null) {
            var modified = query.Query.Accept(new CustomInVisitor(_clientIds));
            interceptionContext.Result = new DbQueryCommandTree(query.MetadataWorkspace, query.DataSpace, modified);
        }
    }

    private class CustomInVisitor : DefaultExpressionVisitor {
        private readonly int[] _clientIds;

        public CustomInVisitor(int[] clientIds) {
            _clientIds = clientIds;
        }

        public override DbExpression Visit(DbScanExpression expression) {
            var table = (EntityType) expression.Target.ElementType;
            // obviously use another way to filter
            // here I just check if there is Clients navigation property
            var prop = table.NavigationProperties.FirstOrDefault(c => c.Name == "Clients");
            if (prop == null)
                return expression;
            var binding = expression.Bind();
            // building x => x.Clients
            var propFilter = binding.VariableType
                .Variable(binding.VariableName)
                .Property(prop);
            // building list of DbConstantExpressions for In clause
            var list = _clientIds.Select(item => DbExpressionBuilder.Constant(item)).ToList();
            // building x => x.Clients.Any(client => clientIds.Contains(client.Id))
            var any = propFilter.Any(exp => exp.Property("Id").In(list));
            return binding.Filter(any);
        }
    }
}