Datei: NDODLL/SqlPersistenceHandling/FromGenerator.cs
Last Commit (b95968d)
| 1 | using System; |
| 2 | using System.Collections.Generic; |
| 3 | using System.Linq; |
| 4 | using System.Text; |
| 5 | using NDOql.Expressions; |
| 6 | using NDO.Mapping; |
| 7 | using NDO.Query.JoinExpressions; |
| 8 | |
| 9 | namespace NDO.SqlPersistenceHandling |
| 10 | { |
| 11 | ····/// <summary> |
| 12 | ····/// Helper class to generate Column names of the select statement |
| 13 | ····/// </summary> |
| 14 | ····internal class FromGenerator |
| 15 | ····{ |
| 16 | ········Class cls; |
| 17 | ········Dictionary<Relation, Class> relationContext; |
| 18 | ········NDOMapping mappings; |
| 19 | ········static readonly string anKey = "from"; |
| 20 | |
| 21 | ········internal FromGenerator( Class cls, Dictionary<Relation, Class> relationContext ) |
| 22 | ········{ |
| 23 | ············this.cls = cls; |
| 24 | ············this.mappings = cls.Parent; |
| 25 | ············this.relationContext = relationContext; |
| 26 | ········} |
| 27 | |
| 28 | ········internal string GenerateFromExpression(OqlExpression expressionTree, List<Relation> prefetchRelations = null) |
| 29 | ········{ |
| 30 | ············StringBuilder sb = new StringBuilder(); |
| 31 | ············AnnotateExpressionTree( expressionTree, prefetchRelations ); |
| 32 | ············if (expressionTree != null) |
| 33 | ············{ |
| 34 | ················List<IdentifierExpression> identifiers = expressionTree.GetAll( e => e is IdentifierExpression && !String.Empty.Equals( e.GetAnnotation<string>(anKey) ) ).Select( e => (IdentifierExpression)e ).ToList(); |
| 35 | ················identifiers.Sort( ( i1, i2 ) => ((string)i1.Value).CompareTo( (string)i2.Value ) ); |
| 36 | ················bool isFirst = true; |
| 37 | ················foreach (IdentifierExpression exp in identifiers) |
| 38 | ················{ |
| 39 | ····················if (!String.IsNullOrEmpty( exp.GetAnnotation<string>(anKey) )) |
| 40 | ····················{ |
| 41 | ························if (isFirst) |
| 42 | ························{ |
| 43 | ····························sb.Append( ' ' ); |
| 44 | ····························isFirst = false; |
| 45 | ························} |
| 46 | ························sb.Append( exp.GetAnnotation<string>( anKey ) ); |
| 47 | ························sb.Append( ' ' ); |
| 48 | ····················} |
| 49 | ················} |
| 50 | |
| 51 | ················if (sb.Length > 0) |
| 52 | ················{ |
| 53 | ····················sb.Length--; |
| 54 | ················} |
| 55 | ············} |
| 56 | ············return "FROM " + cls.GetQualifiedTableName() + sb.ToString(); |
| 57 | ········} |
| 58 | |
| 59 | ········private void AnnotateExpressionTree( OqlExpression expressionTree, List<Relation> prefetchRelations ) |
| 60 | ········{ |
| 61 | ············HashSet<Relation> allJoins = new HashSet<Relation>(); |
| 62 | ············if (prefetchRelations != null) |
| 63 | ············{ |
| 64 | ················// if a prefetch relation is bidirectional, |
| 65 | ················// this will prevent adding the relation into the joins twice |
| 66 | ················foreach(var rel in prefetchRelations) |
| 67 | ················allJoins.Add( rel ); |
| 68 | ················// We know, that this must be a prefetch, so the direction |
| 69 | ················// of the relation is reversed. |
| 70 | #warning Hier muss noch die Annotation rein |
| 71 | ············} |
| 72 | |
| 73 | ············if (expressionTree == null) |
| 74 | ················return; |
| 75 | |
| 76 | ············foreach (IdentifierExpression exp in expressionTree.GetAll( e => e is IdentifierExpression )) |
| 77 | ············{ |
| 78 | ················string fullName = (string)exp.Value; |
| 79 | ················if (fullName.IndexOf( '.' ) < 0) |
| 80 | ····················continue; |
| 81 | |
| 82 | ················StringBuilder sb = new StringBuilder(); |
| 83 | ················string[] arr = ((string)exp.Value).Split( '.' ); |
| 84 | ················Class startClass = this.cls; |
| 85 | ················bool isFirst = true; |
| 86 | |
| 87 | ················for (int i = 0; i < arr.Length - 1; i++)··// at least the last element is the field name |
| 88 | ················{ |
| 89 | ····················string relationName = arr[i]; |
| 90 | |
| 91 | ····················if (relationName == "oid") |
| 92 | ························break; |
| 93 | |
| 94 | ····················Relation relation = startClass.FindRelation( relationName ); |
| 95 | |
| 96 | ····················if (relation == null) |
| 97 | ························break; |
| 98 | |
| 99 | ····················if (allJoins.Contains( relation )) |
| 100 | ························continue; |
| 101 | |
| 102 | ····················allJoins.Add( relation ); |
| 103 | |
| 104 | ····················Class childClass = this.relationContext.ContainsKey( relation ) |
| 105 | ························? this.relationContext[relation] |
| 106 | ························: this.mappings.FindClass( relation.ReferencedType ); |
| 107 | |
| 108 | ····················if (!isFirst) |
| 109 | ························sb.Append( ' ' ); |
| 110 | |
| 111 | ····················// 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. |
| 112 | ····················// It's sufficient to compare against the foreign keys stored in the owner class' table. |
| 113 | ····················if ((relation.Multiplicity == RelationMultiplicity.List || relation.MappingTable != null) || arr[i + 1] != "oid") |
| 114 | ························sb.Append( new InnerJoinExpression( relation, this.relationContext, arr[i + 1] == "oid" ).ToString() ); |
| 115 | |
| 116 | ····················startClass = childClass; |
| 117 | ····················isFirst = false; |
| 118 | ················} |
| 119 | ················string join = sb.ToString(); |
| 120 | ················exp.SetAnnotation( anKey, join ); |
| 121 | ············} |
| 122 | ········} |
| 123 | ····} |
| 124 | } |
| 125 |
New Commit (42d0ae7)
| 1 | using System; |
| 2 | using System.Collections.Generic; |
| 3 | using System.Linq; |
| 4 | using System.Text; |
| 5 | using NDOql.Expressions; |
| 6 | using NDO.Mapping; |
| 7 | using NDO.Query.JoinExpressions; |
| 8 | |
| 9 | namespace NDO.SqlPersistenceHandling |
| 10 | { |
| 11 | ····/// <summary> |
| 12 | ····/// Helper class to generate Column names of the select statement |
| 13 | ····/// </summary> |
| 14 | ····internal class FromGenerator |
| 15 | ····{ |
| 16 | ········Class cls; |
| 17 | ········Dictionary<Relation, Class> relationContext; |
| 18 | ········NDOMapping mappings; |
| 19 | ········static readonly string anKey = "from"; |
| 20 | |
| 21 | ········internal FromGenerator( Class cls, Dictionary<Relation, Class> relationContext ) |
| 22 | ········{ |
| 23 | ············this.cls = cls; |
| 24 | ············this.mappings = cls.Parent; |
| 25 | ············this.relationContext = relationContext; |
| 26 | ········} |
| 27 | |
| 28 | ········internal string GenerateFromExpression(OqlExpression expressionTree, List<Relation> prefetchRelations = null) |
| 29 | ········{ |
| 30 | ············StringBuilder sb = new StringBuilder(); |
| 31 | ············AnnotateExpressionTree( expressionTree, prefetchRelations ); |
| 32 | ············if (expressionTree != null) |
| 33 | ············{ |
| 34 | ················List<IdentifierExpression> identifiers = expressionTree.GetAll( e => e is IdentifierExpression && !String.Empty.Equals( e.GetAnnotation<string>(anKey) ) ).Select( e => (IdentifierExpression)e ).ToList(); |
| 35 | ················identifiers.Sort( ( i1, i2 ) => ((string)i1.Value).CompareTo( (string)i2.Value ) ); |
| 36 | ················bool isFirst = true; |
| 37 | ················foreach (IdentifierExpression exp in identifiers) |
| 38 | ················{ |
| 39 | ····················if (!String.IsNullOrEmpty( exp.GetAnnotation<string>(anKey) )) |
| 40 | ····················{ |
| 41 | ························if (isFirst) |
| 42 | ························{ |
| 43 | ····························sb.Append( ' ' ); |
| 44 | ····························isFirst = false; |
| 45 | ························} |
| 46 | ························sb.Append( exp.GetAnnotation<string>( anKey ) ); |
| 47 | ························sb.Append( ' ' ); |
| 48 | ····················} |
| 49 | ················} |
| 50 | |
| 51 | ················if (sb.Length > 0) |
| 52 | ················{ |
| 53 | ····················sb.Length--; |
| 54 | ················} |
| 55 | ············} |
| 56 | ············return "FROM " + cls.GetQualifiedTableName() + sb.ToString(); |
| 57 | ········} |
| 58 | |
| 59 | ········private void AnnotateExpressionTree( OqlExpression expressionTree, List<Relation> prefetchRelations ) |
| 60 | ········{ |
| 61 | ············HashSet<Relation> allJoins = new HashSet<Relation>(); |
| 62 | ············if (prefetchRelations != null) |
| 63 | ············{ |
| 64 | ················// if a prefetch relation is bidirectional, |
| 65 | ················// this will prevent adding the relation into the joins twice |
| 66 | ················foreach(var rel in prefetchRelations) |
| 67 | ················allJoins.Add( rel ); |
| 68 | ················// We know, that this must be a prefetch, so the direction |
| 69 | ················// of the relation is reversed. |
| 70 | |
| 71 | ················//TODO: We need to implement the annotation here. |
| 72 | ············} |
| 73 | |
| 74 | ············if (expressionTree == null) |
| 75 | ················return; |
| 76 | |
| 77 | ············foreach (IdentifierExpression exp in expressionTree.GetAll( e => e is IdentifierExpression )) |
| 78 | ············{ |
| 79 | ················string fullName = (string)exp.Value; |
| 80 | ················if (fullName.IndexOf( '.' ) < 0) |
| 81 | ····················continue; |
| 82 | |
| 83 | ················StringBuilder sb = new StringBuilder(); |
| 84 | ················string[] arr = ((string)exp.Value).Split( '.' ); |
| 85 | ················Class startClass = this.cls; |
| 86 | ················bool isFirst = true; |
| 87 | |
| 88 | ················for (int i = 0; i < arr.Length - 1; i++)··// at least the last element is the field name |
| 89 | ················{ |
| 90 | ····················string relationName = arr[i]; |
| 91 | |
| 92 | ····················if (relationName == "oid") |
| 93 | ························break; |
| 94 | |
| 95 | ····················Relation relation = startClass.FindRelation( relationName ); |
| 96 | |
| 97 | ····················if (relation == null) |
| 98 | ························break; |
| 99 | |
| 100 | ····················if (allJoins.Contains( relation )) |
| 101 | ························continue; |
| 102 | |
| 103 | ····················allJoins.Add( relation ); |
| 104 | |
| 105 | ····················Class childClass = this.relationContext.ContainsKey( relation ) |
| 106 | ························? this.relationContext[relation] |
| 107 | ························: this.mappings.FindClass( relation.ReferencedType ); |
| 108 | |
| 109 | ····················if (!isFirst) |
| 110 | ························sb.Append( ' ' ); |
| 111 | |
| 112 | ····················// 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. |
| 113 | ····················// It's sufficient to compare against the foreign keys stored in the owner class' table. |
| 114 | ····················if ((relation.Multiplicity == RelationMultiplicity.List || relation.MappingTable != null) || arr[i + 1] != "oid") |
| 115 | ························sb.Append( new InnerJoinExpression( relation, this.relationContext, arr[i + 1] == "oid" ).ToString() ); |
| 116 | |
| 117 | ····················startClass = childClass; |
| 118 | ····················isFirst = false; |
| 119 | ················} |
| 120 | ················string join = sb.ToString(); |
| 121 | ················exp.SetAnnotation( anKey, join ); |
| 122 | ············} |
| 123 | ········} |
| 124 | ····} |
| 125 | } |
| 126 |