public override void OnBeforeFromClauseVisited(Expression expression) { base.OnBeforeFromClauseVisited(expression); // TODO: Move into OnBeforeSelectClauseVisited. if (expression is ConstantExpression) { ConstantExpression constantExpression = expression as ConstantExpression; IQueryable queryable = constantExpression.Value as IQueryable; if (queryable != null && typeof(Resource).IsAssignableFrom(queryable.ElementType)) { SparqlVariable s = VariableGenerator.GlobalSubject; SetSubjectVariable(s); VariableGenerator.SetSubjectVariable(expression, s); } else { throw new NotSupportedException(constantExpression.Value.GetType().ToString()); } } else { // TODO: Create unit test for QuerySourceReferenceExpression, SubQueryExpression throw new NotImplementedException(expression.GetType().ToString()); } }
private SparqlVariable BuildMemberAccess(MemberExpression memberExpression, IGraphPatternBuilder patternBuilder) { MemberInfo member = memberExpression.Member; // If we do access a member of a system type, like string.Length we actually select the // the declaring member and invoke a SPARQL built in call to get the value. if (member.IsBuiltInCall()) { MemberExpression parentMember = memberExpression.Expression as MemberExpression; return(BuildMemberAccess(parentMember, patternBuilder)); } else if (memberExpression.Expression is MemberExpression) { MemberExpression parentMember = memberExpression.Expression as MemberExpression; // Note: When we build an optional property path, we consider the relation to the // parent properties of the accessed property to be non-optional. IGraphPatternBuilder builder = member.IsUriType() ? patternBuilder : PatternBuilder; // We might encounter property paths (i.e. contact.Organization.Name). Therefore, // implement the parent expression of the current member recursively.. SparqlVariable po = BuildMemberAccess(parentMember, builder); // If we are building a node on a property path (parentExpression != null), we associate // the object variable with the parent expression so that it becomes the subject of the parent. VariableGenerator.SetSubjectVariable(memberExpression, po); } if (member.IsUriType()) { // When we access the .Uri member of a resource we do not need a property mapping and return the subject as the bound variable. // We create a triple pattern describing the resource in the local scope just in case it has not been described yet. // Todo: Improve. Check if triples actually need to be asserted. SparqlVariable s = VariableGenerator.TryGetSubjectVariable(memberExpression) ?? SubjectVariable; SparqlVariable p = VariableGenerator.CreatePredicateVariable(); SparqlVariable o = VariableGenerator.CreateObjectVariable(memberExpression); patternBuilder.Where(t => t.Subject(s).Predicate(p).Object(o)); VariableGenerator.SetSubjectVariable(memberExpression, s); return(s); } else if (memberExpression.Expression is QuerySourceReferenceExpression) { QuerySourceReferenceExpression querySource = memberExpression.Expression as QuerySourceReferenceExpression; if (VariableGenerator.TryGetSubjectVariable(memberExpression) == VariableGenerator.GlobalSubject) { // In case the accessed member is the global query subject (i.e. from x select x.Y).. SparqlVariable s = VariableGenerator.TryGetSubjectVariable(querySource); SparqlVariable o = VariableGenerator.GlobalSubject; if (s == null) { s = VariableGenerator.CreateSubjectVariable(querySource); BuildMemberAccess(memberExpression, patternBuilder, member, s, o); } return(o); } else { // Otherwise we are accessing a member of the globale query subject (i.e. from x where x.Y select x) SparqlVariable s = VariableGenerator.TryGetSubjectVariable(querySource) ?? VariableGenerator.GlobalSubject; SparqlVariable o = VariableGenerator.TryGetObjectVariable(memberExpression) ?? VariableGenerator.CreateObjectVariable(memberExpression); BuildMemberAccess(memberExpression, patternBuilder, member, s, o); return(o); } } else { SparqlVariable s = VariableGenerator.TryGetSubjectVariable(memberExpression) ?? VariableGenerator.CreateSubjectVariable(memberExpression); SparqlVariable o = VariableGenerator.TryGetObjectVariable(memberExpression) ?? VariableGenerator.CreateObjectVariable(memberExpression); BuildMemberAccess(memberExpression, patternBuilder, member, s, o); return(o); } }
public override void OnBeforeSelectClauseVisited(Expression selector) { base.OnBeforeSelectClauseVisited(selector); Type selectedType = TryGetSelectedType(selector); if (selectedType == null || !typeof(Resource).IsAssignableFrom(selectedType)) { throw new NotSupportedException(selectedType.ToString()); } // 1. We always create an outer query which selects all triples that describe our resources. SparqlVariable s_ = VariableGenerator.GlobalSubject; SparqlVariable p_ = VariableGenerator.GlobalPredicate; SparqlVariable o_ = VariableGenerator.GlobalObject; VariableGenerator.SetSubjectVariable(selector, s_); VariableGenerator.SetPredicateVariable(selector, p_); VariableGenerator.SetObjectVariable(selector, o_); SetSubjectVariable(s_); SetObjectVariable(o_); SelectVariable(s_); SelectVariable(p_); SelectVariable(o_); WhereResource(s_, p_, o_); // If we are describing resources using a SKIP or TAKE operator, we need to make sure that // these operations are on a per-resource basis and all triples for the described resources // are contained in the result. if (QueryModel.HasResultOperator <SkipResultOperator>() || QueryModel.HasResultOperator <TakeResultOperator>() || QueryModel.HasResultOperator <FirstResultOperator>() || QueryModel.HasResultOperator <LastResultOperator>()) { // ..which are described in an inner query on which the LIMIT and OFFSET operators are set. // This results in a SELECT query that acts like a DESCRIBE but ist faster on most triple // stores as the triples can be returend via bindings and must not be parsed. ISparqlQueryGenerator subGenerator = QueryGeneratorTree.CreateSubQueryGenerator(this, selector); subGenerator.SetSubjectVariable(s_, true); subGenerator.SetObjectVariable(o_); GenerateTypeConstraintOnSubject(subGenerator, selector); QueryGeneratorTree.CurrentGenerator = subGenerator; // NOTE: We set the subGenerator as a child *AFTER* the select clause and body clauses // have been processed (see <c>OnSelectClauseVisited</c>). This is because the dotNetRDF // query generator does not correctly handle result operators when it is already set as a child. } else if (!QueryModel.HasTypeConstraintOnExpression(selector)) { // NOTE: This should not be done here. Simply because the HasTypeConstraintOnExpression // requires us to look ahead at the body clauses which is already done in more detail // by the expression visitor. We need a way to generate the type constraint after the query // has been visited and no type constraint was generated. GenerateTypeConstraintOnSubject(this, selector); } if (selector is MemberExpression) { MemberExpression memberExpression = selector as MemberExpression; BuildMemberAccess(memberExpression); } }