/// <summary> /// Get the where clause of the SQL string /// </summary> /// <returns>Where clause string</returns> public QueryContexts GetContexts(Class resultClass, OqlExpression expressionTree) { var result = new QueryContexts(); if (expressionTree == null) { return(result); } this.names = (from oex in expressionTree.GetAll(e => e is IdentifierExpression) select(string) oex.Value).ToList(); this.allRelations = new HashSet <Relation>(); if (names.Count == 0) { return(result); } foreach (string name in names) { CreateContextForName(resultClass, name, allRelations); } if (allRelations.Count > 0) { this.relations = new List <Relation>(); foreach (var de in allRelations) { relations.Add(de); } BuildMutations(0, result, new Stack <Class>()); } return(result); }
internal string GenerateFromExpression(OqlExpression expressionTree, List <Relation> prefetchRelations = null) { StringBuilder sb = new StringBuilder(); AnnotateExpressionTree(expressionTree, prefetchRelations); if (expressionTree != null) { List <IdentifierExpression> identifiers = expressionTree.GetAll(e => e is IdentifierExpression && !String.Empty.Equals(e.GetAnnotation <string>(anKey))).Select(e => (IdentifierExpression)e).ToList(); identifiers.Sort((i1, i2) => ((string)i1.Value).CompareTo((string)i2.Value)); bool isFirst = true; foreach (IdentifierExpression exp in identifiers) { if (!String.IsNullOrEmpty(exp.GetAnnotation <string>(anKey))) { if (isFirst) { sb.Append(' '); isFirst = false; } sb.Append(exp.GetAnnotation <string>(anKey)); sb.Append(' '); } } if (sb.Length > 0) { sb.Length--; } } return("FROM " + cls.GetQualifiedTableName() + sb.ToString()); }
private void MoveParameterExpression(OqlExpression expressionTree, int fromOrdinal, int additionalSpace) { if (additionalSpace == 0) { return; } // Moves the ordinal numbers of ParameterExpressions above the current expression to leave parameters for // the additional columns. foreach (ParameterExpression parExp in expressionTree.GetAll(e => { ParameterExpression pe = e as ParameterExpression; if (pe == null) { return(false); } return(pe.Ordinal > fromOrdinal); })) { parExp.Ordinal += additionalSpace; } }
private void AnnotateExpressionTree(OqlExpression expressionTree) { foreach (ParameterExpression parExp in expressionTree.GetAll(e => e is ParameterExpression).ToList()) { if (Guid.Empty.Equals(parExp.ParameterValue) || DateTime.MinValue.Equals(parExp.ParameterValue)) { var parent = parExp.Parent; if (parent.Operator == "=") { var i = parent.Children.IndexOf(parExp); var nullExp = new NamedConstantExpression("NULL", false, 0, 0); parent.Children[i] = nullExp; ((IManageExpression)nullExp).SetParent(parent); parent.Operator = "IS"; } if (parent.Operator == "<>") { var i = parent.Children.IndexOf(parExp); var nullExp = new NamedConstantExpression("NULL", true, 0, 0); parent.Children[i] = nullExp; ((IManageExpression)nullExp).SetParent(parent); parent.Operator = "IS"; } } } foreach (IdentifierExpression exp in expressionTree.GetAll(e => e is IdentifierExpression).ToList()) { string[] arr = ((string)exp.Value).Split('.'); string fieldName = arr[arr.Length - 1]; // In case of embedded or value types this will be overwritten Relation relation; Class parentClass = GetParentClass(exp, arr, out fieldName, out relation); if (fieldName == "oid") { string[] oidColumns = (from c in parentClass.Oid.OidColumns select QualifiedColumnName.Get(c)).ToArray(); if (relation != null) { // In these cases we don't need the join to the table of the class owning the oid. // It's sufficient to compare against the foreign keys stored in the owner class' table // or in the mapping table if (relation.MappingTable != null) { oidColumns = (from c in relation.MappingTable.ChildForeignKeyColumns select QualifiedColumnName.Get(relation.MappingTable, c)).ToArray(); } else if (relation.Multiplicity == RelationMultiplicity.Element) { oidColumns = (from c in relation.ForeignKeyColumns select QualifiedColumnName.Get(c)).ToArray(); } } ParameterExpression parExp = exp.Siblings[0] as ParameterExpression; var isDirectSingleExpression = exp.Parent.Operator != "=" || oidColumns.Length == 1 && exp.Siblings[0] is ConstantExpression; // like "oid = 123" if (parExp == null && !isDirectSingleExpression) { throw new QueryException(10010, $"Expression '{exp.ToString()}' resolves to an oid. It's sibling expression must be a ParameterExpression. But the sibling is {exp.Siblings[0]}"); } object[] oidKeys = null; if (!isDirectSingleExpression) { // split the ObjectId or an array into individual parameters oidKeys = ExtractOidKeys(parExp); // Now set the parameter value of the first column if (oidKeys != null) { parExp.ParameterValue = oidKeys[0]; } } if (oidColumns.Length > 1 && exp.Children.Count == 0) { OqlExpression equalsExpression = exp.Parent; // Must be a = expression like 'xxx.oid = {0}'. // We need some additional parameters for the additional columns. MoveParameterExpression(expressionTree, parExp.Ordinal, oidColumns.Length - 1); // Replace the parent expression with a new AND expression OqlExpression andExpression = new OqlExpression(0, 0); ((IManageExpression)andExpression).SetParent(equalsExpression.Parent); equalsExpression.Parent.Children.Remove(equalsExpression); equalsExpression.Parent.Add(andExpression); // We need to set Parent and Child explicitly. // See comment in IManageExpression.SetParent. // Reuse the original equality expression as first child of the AND expression ((IManageExpression)equalsExpression).SetParent(andExpression); andExpression.Add(equalsExpression); exp.SetAnnotation(anKey, oidColumns[0]); int currentOrdinal = parExp.Ordinal; // Now add the additional children of the AND expression for (int i = 1; i < oidColumns.Length; i++) { OqlExpression newParent = equalsExpression.DeepClone; // equality expression and it's both children andExpression.Add(newParent, "AND"); ((IManageExpression)newParent).SetParent(andExpression); // Now patch the Annotation and a new parameter to the children IdentifierExpression newIdentExp = (IdentifierExpression)newParent.Children.Where(e => e is IdentifierExpression).First(); newIdentExp.SetAnnotation(anKey, oidColumns[i]); ParameterExpression newParExp = (ParameterExpression)newParent.Children.Where(e => e is ParameterExpression).First(); if (oidKeys != null) { newParExp.ParameterValue = oidKeys[i]; } newParExp.Ordinal = ++currentOrdinal; } } else { int index = 0; if (exp.Children.Count > 0 && exp.Children[0] is IndexExpression) { index = (int)exp.Children[0].Value; } if (index >= oidColumns.Length) { throw new IndexOutOfRangeException("oid index exceeds oid column count"); } exp.SetAnnotation(anKey, oidColumns[index]); } } else { Field field = parentClass.FindField(fieldName); if (field != null) { exp.SetAnnotation(anKey, QualifiedColumnName.Get(field.Column)); } else { Relation oneTooneRelation = parentClass.Relations.FirstOrDefault(r => r.Multiplicity == RelationMultiplicity.Element && (r.FieldName == fieldName || r.AccessorName == fieldName)); if (oneTooneRelation != null) { exp.SetAnnotation(anKey, QualifiedColumnName.Get(oneTooneRelation.ForeignKeyColumns.First())); } else { throw new Exception("Can't find Field mapping for " + fieldName + " in " + exp.Value); } } } } }
private void AnnotateExpressionTree(OqlExpression expressionTree, List <Relation> prefetchRelations) { HashSet <Relation> allJoins = new HashSet <Relation>(); if (prefetchRelations != null) { // if a prefetch relation is bidirectional, // this will prevent adding the relation into the joins twice foreach (var rel in prefetchRelations) { allJoins.Add(rel); } // We know, that this must be a prefetch, so the direction // of the relation is reversed. #warning Hier muss noch die Annotation rein } if (expressionTree == null) { return; } foreach (IdentifierExpression exp in expressionTree.GetAll(e => e is IdentifierExpression)) { string fullName = (string)exp.Value; if (fullName.IndexOf('.') < 0) { continue; } StringBuilder sb = new StringBuilder(); string[] arr = ((string)exp.Value).Split('.'); Class startClass = this.cls; bool isFirst = true; for (int i = 0; i < arr.Length - 1; i++) // at least the last element is the field name { string relationName = arr[i]; if (relationName == "oid") { break; } Relation relation = startClass.FindRelation(relationName); if (relation == null) { break; } if (allJoins.Contains(relation)) { continue; } allJoins.Add(relation); Class childClass = this.relationContext.ContainsKey(relation) ? this.relationContext[relation] : this.mappings.FindClass(relation.ReferencedType); if (!isFirst) { sb.Append(' '); } // In the cases where the following condition doesn't apply, we don't need the join to the table of the class owning the oid. // It's sufficient to compare against the foreign keys stored in the owner class' table. if ((relation.Multiplicity == RelationMultiplicity.List || relation.MappingTable != null) || arr[i + 1] != "oid") { sb.Append(new InnerJoinExpression(relation, this.relationContext, arr[i + 1] == "oid").ToString()); } startClass = childClass; isFirst = false; } string join = sb.ToString(); exp.SetAnnotation(anKey, join); } }