protected override Expression VisitSubQueryExpression(SubQueryExpression expression) { if (expression.QueryModel.ResultOperators.Count == 1 && expression.QueryModel.ResultOperators[0] is ContainsResultOperator) { var contains = expression.QueryModel.ResultOperators[0] as ContainsResultOperator; if (expression.QueryModel.MainFromClause.FromExpression.NodeType == ExpressionType.Constant && contains.Item is MemberExpression) { var itemExpression = VisitExpression(contains.Item); if (itemExpression is SelectVariableNameExpression) { // We can translate the subquery to an IN expression _filterWriter.WriteInFilter(contains.Item, expression.QueryModel.MainFromClause.FromExpression); return(expression); } } else if (expression.QueryModel.MainFromClause.FromExpression.NodeType == ExpressionType.MemberAccess) { var itemExpression = VisitExpression(expression.QueryModel.MainFromClause.FromExpression); if (itemExpression is SelectVariableNameExpression) { _filterWriter.WriteInFilter(expression.QueryModel.MainFromClause.FromExpression, contains.Item); return(expression); } } } if (expression.QueryModel.ResultOperators.Count == 1 && expression.QueryModel.ResultOperators[0] is AllResultOperator) { var all = expression.QueryModel.ResultOperators[0] as AllResultOperator; if (all != null) { FilterWriter existingWriter = _filterWriter; _filterWriter = new FilterWriter(this, this.QueryBuilder, new StringBuilder()); QueryBuilder.StartNotExists(); var mappedExpression = VisitExpression(expression.QueryModel.MainFromClause.FromExpression); QueryBuilder.AddQuerySourceMapping(expression.QueryModel.MainFromClause, mappedExpression); _filterWriter.WriteInvertedFilterPredicate(all.Predicate); QueryBuilder.AddFilterExpression(_filterWriter.FilterExpression); QueryBuilder.EndNotExists(); _filterWriter = existingWriter; return(expression); } } if (expression.QueryModel.ResultOperators.Count == 1 && expression.QueryModel.ResultOperators[0] is AnyResultOperator) { QueryBuilder.StartExists(); var outerFilterWriter = _filterWriter; _filterWriter = new FilterWriter(this, QueryBuilder, new StringBuilder()); var itemVarName = SparqlQueryBuilder.SafeSparqlVarName(expression.QueryModel.MainFromClause.ItemName); var mappedFromExpression = VisitExpression(expression.QueryModel.MainFromClause.FromExpression); QueryBuilder.AddQuerySourceMapping(expression.QueryModel.MainFromClause, mappedFromExpression); if (mappedFromExpression is SelectVariableNameExpression) { QueryBuilder.RenameVariable((mappedFromExpression as SelectVariableNameExpression).Name, itemVarName); } foreach (var bodyClause in expression.QueryModel.BodyClauses) { if (bodyClause is WhereClause) { var whereClause = bodyClause as WhereClause; VisitExpression(whereClause.Predicate); } else { CreateUnhandledItemException(bodyClause, "VisitSubQueryExpression"); } } var innerFilter = _filterWriter.ToString(); if (!String.IsNullOrEmpty(innerFilter)) { QueryBuilder.AddFilterExpression(innerFilter); } _filterWriter = outerFilterWriter; QueryBuilder.EndExists(); return(expression); } else if (expression.QueryModel.ResultOperators.Count == 0) { var itemVarName = SparqlQueryBuilder.SafeSparqlVarName(expression.QueryModel.MainFromClause.ItemName); var mappedFromExpression = VisitExpression(expression.QueryModel.MainFromClause.FromExpression); QueryBuilder.AddQuerySourceMapping(expression.QueryModel.MainFromClause, mappedFromExpression); if (mappedFromExpression is SelectVariableNameExpression) { // Rename the variable in the SPARQL so that it matches the LINQ variable QueryBuilder.RenameVariable((mappedFromExpression as SelectVariableNameExpression).Name, itemVarName); (mappedFromExpression as SelectVariableNameExpression).Name = itemVarName; } foreach (var bodyClause in expression.QueryModel.BodyClauses) { if (bodyClause is WhereClause) { var whereClause = bodyClause as WhereClause; VisitExpression(whereClause.Predicate); } else { CreateUnhandledItemException(bodyClause, "VisitSubQueryExpression"); } } return(mappedFromExpression); } return(base.VisitSubQueryExpression(expression)); }
protected override Expression VisitSubQueryExpression(SubQueryExpression expression) { if (expression.QueryModel.ResultOperators.Count == 1 && expression.QueryModel.ResultOperators[0] is ContainsResultOperator) { var contains = (ContainsResultOperator)expression.QueryModel.ResultOperators[0]; if (expression.QueryModel.MainFromClause.FromExpression.NodeType == ExpressionType.Constant && contains.Item is MemberExpression) { var memberExpression = (MemberExpression)contains.Item; var itemExpression = VisitExpression(contains.Item); var varNameExpression = itemExpression as SelectVariableNameExpression; if (varNameExpression != null) { if (IsIdInArraySubQuery(memberExpression, expression.QueryModel.MainFromClause.FromExpression)) { var varName = varNameExpression.Name; // The subquery is a filter on a resource IRI // It is more efficient to use a UNION of BIND triple patterns than a FILTER var values = ((ConstantExpression)expression.QueryModel.MainFromClause.FromExpression).Value as IEnumerable; if (values != null) { var identifierProperty = memberExpression.Member as PropertyInfo; QueryBuilder.StartUnion(); foreach (var value in values) { QueryBuilder.StartUnionElement(); QueryBuilder.AddBindExpression( "<" + QueryBuilder.Context.MapIdToUri(identifierProperty, value.ToString()) + ">", varName); QueryBuilder.EndUnionElement(); } QueryBuilder.EndUnion(); return(expression); } return(base.VisitSubQueryExpression(expression)); } else { // The subquery is a filter on a resource property expression // We can translate the subquery to an IN expression _filterWriter.WriteInFilter(itemExpression, expression.QueryModel.MainFromClause.FromExpression); return(expression); } } } else if (expression.QueryModel.MainFromClause.FromExpression.NodeType == ExpressionType.MemberAccess) { var itemExpression = VisitExpression(expression.QueryModel.MainFromClause.FromExpression); if (itemExpression is SelectVariableNameExpression) { _filterWriter.WriteInFilter(expression.QueryModel.MainFromClause.FromExpression, contains.Item); return(expression); } } } if (expression.QueryModel.ResultOperators.Count == 1 && expression.QueryModel.ResultOperators[0] is AllResultOperator) { var all = (AllResultOperator)expression.QueryModel.ResultOperators[0]; var existingWriter = _filterWriter; _filterWriter = new FilterWriter(this, QueryBuilder, new StringBuilder()); // TODO: Could check FromExpression to see if it is optimisable QueryBuilder.StartNotExists(); var mappedExpression = VisitExpression(expression.QueryModel.MainFromClause.FromExpression); QueryBuilder.AddQuerySourceMapping(expression.QueryModel.MainFromClause, mappedExpression); _filterWriter.WriteInvertedFilterPredicate(all.Predicate); QueryBuilder.AddFilterExpression(_filterWriter.FilterExpression); QueryBuilder.EndNotExists(); _filterWriter = existingWriter; return(expression); } if (expression.QueryModel.ResultOperators.Count == 1 && expression.QueryModel.ResultOperators[0] is AnyResultOperator) { QueryBuilder.StartExists(); var outerFilterWriter = _filterWriter; _filterWriter = new FilterWriter(this, QueryBuilder, new StringBuilder()); var itemVarName = SparqlQueryBuilder.SafeSparqlVarName(expression.QueryModel.MainFromClause.ItemName); var mappedFromExpression = VisitExpression(expression.QueryModel.MainFromClause.FromExpression); QueryBuilder.AddQuerySourceMapping(expression.QueryModel.MainFromClause, mappedFromExpression); if (mappedFromExpression is SelectVariableNameExpression) { QueryBuilder.RenameVariable((mappedFromExpression as SelectVariableNameExpression).Name, itemVarName); } foreach (var bodyClause in expression.QueryModel.BodyClauses) { if (bodyClause is WhereClause) { var whereClause = bodyClause as WhereClause; VisitExpression(whereClause.Predicate); } else { CreateUnhandledItemException(bodyClause, "VisitSubQueryExpression"); } } var innerFilter = _filterWriter.ToString(); if (!string.IsNullOrEmpty(innerFilter)) { QueryBuilder.AddFilterExpression(innerFilter); } _filterWriter = outerFilterWriter; QueryBuilder.EndExists(); return(expression); } else if (expression.QueryModel.ResultOperators.Count == 0) { var itemVarName = SparqlQueryBuilder.SafeSparqlVarName(expression.QueryModel.MainFromClause.ItemName); var mappedFromExpression = VisitExpression(expression.QueryModel.MainFromClause.FromExpression); QueryBuilder.AddQuerySourceMapping(expression.QueryModel.MainFromClause, mappedFromExpression); if (mappedFromExpression is SelectVariableNameExpression) { // Rename the variable in the SPARQL so that it matches the LINQ variable QueryBuilder.RenameVariable((mappedFromExpression as SelectVariableNameExpression).Name, itemVarName); (mappedFromExpression as SelectVariableNameExpression).Name = itemVarName; } foreach (var bodyClause in expression.QueryModel.BodyClauses) { if (bodyClause is WhereClause) { var whereClause = bodyClause as WhereClause; VisitExpression(whereClause.Predicate); } else { CreateUnhandledItemException(bodyClause, "VisitSubQueryExpression"); } } return(mappedFromExpression); } return(base.VisitSubQueryExpression(expression)); }