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 |