Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Mapping / ViewGeneration / Structures / TypeConstant.cs
1 //---------------------------------------------------------------------
2 // <copyright file="TypeConstant.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9
10 using System.Text;
11 using System.Collections.Generic;
12 using System.Data.Mapping.ViewGeneration.CqlGeneration;
13 using System.Data.Common;
14 using System.Data.Common.CommandTrees;
15 using System.Data.Common.CommandTrees.ExpressionBuilder;
16 using System.Data.Common.Utils;
17 using System.Data.Metadata.Edm;
18 using System.Diagnostics;
19 using System.Linq;
20
21 namespace System.Data.Mapping.ViewGeneration.Structures
22 {
23     /// <summary>
24     /// A constant for storing type values, e.g., a type constant is used to denote (say) a Person type, Address type, etc.
25     /// It essentially encapsulates an EDM nominal type.
26     /// </summary>
27     internal sealed class TypeConstant : Constant
28     {
29         #region Constructor
30         /// <summary>
31         /// Creates a type constant corresponding to the <paramref name="type"/>.
32         /// </summary>
33         internal TypeConstant(EdmType type)
34         {
35             Debug.Assert(type != null, "type must not be null.");
36             m_edmType = type;
37         }
38         #endregion
39
40         #region Fields
41         /// <summary>
42         /// The EDM type denoted by this type constant.
43         /// </summary>
44         private readonly EdmType m_edmType;
45         #endregion
46
47         #region Properties
48         /// <summary>
49         /// Returns the EDM type corresponding to the type constant.
50         /// </summary>
51         internal EdmType EdmType
52         {
53             get { return m_edmType; }
54         }
55         #endregion
56
57         #region Methods
58         internal override bool IsNull()
59         {
60             return false;
61         }
62
63         internal override bool IsNotNull()
64         {
65             return false;
66         }
67
68         internal override bool IsUndefined()
69         {
70             return false;
71         }
72
73         internal override bool HasNotNull()
74         {
75             return false;
76         }
77
78         protected override bool IsEqualTo(Constant right)
79         {
80             TypeConstant rightTypeConstant = right as TypeConstant;
81             if (rightTypeConstant == null)
82             {
83                 return false;
84             }
85             return m_edmType == rightTypeConstant.m_edmType;
86         }
87
88         public override int GetHashCode()
89         {
90             if (m_edmType == null)
91             { // null type constant
92                 return 0;
93             }
94             else
95             {
96                 return m_edmType.GetHashCode();
97             }
98         }
99
100         internal override StringBuilder AsEsql(StringBuilder builder, MemberPath outputMember, string blockAlias)
101         {
102             AsCql(
103                 // createRef action
104                 (refScopeEntitySet, keyMemberOutputPaths) =>
105                 {
106                     // Construct a scoped reference: CreateRef(CPerson1Set, NewRow(pid1, pid2), CPerson1)
107                     EntityType refEntityType = (EntityType)(((RefType)outputMember.EdmType).ElementType);
108                     builder.Append("CreateRef(");
109                     CqlWriter.AppendEscapedQualifiedName(builder, refScopeEntitySet.EntityContainer.Name, refScopeEntitySet.Name);
110                     builder.Append(", row(");
111                     for (int i = 0; i < keyMemberOutputPaths.Count; ++i)
112                     {
113                         if (i > 0)
114                         {
115                             builder.Append(", ");
116                         }
117                         // Given the member, we need its aliased name
118                         string fullFieldAlias = CqlWriter.GetQualifiedName(blockAlias, keyMemberOutputPaths[i].CqlFieldAlias);
119                         builder.Append(fullFieldAlias);
120                     }
121                     builder.Append("), ");
122                     CqlWriter.AppendEscapedTypeName(builder, refEntityType);
123                     builder.Append(')');
124                 },
125                 // createType action
126                 (membersOutputPaths) =>
127                 {
128                     // Construct an entity/complex/Association type in the Members order for fields: CPerson(CPerson1_Pid, CPerson1_Name)
129                     CqlWriter.AppendEscapedTypeName(builder, m_edmType);
130                     builder.Append('(');
131                     for (int i = 0; i < membersOutputPaths.Count; ++i)
132                     {
133                         if (i > 0)
134                         {
135                             builder.Append(", ");
136                         }
137                         // Given the member, we need its aliased name: CPerson1_Pid
138                         string fullFieldAlias = CqlWriter.GetQualifiedName(blockAlias, membersOutputPaths[i].CqlFieldAlias);
139                         builder.Append(fullFieldAlias);
140                     }
141                     builder.Append(')');
142                 },
143                 outputMember);
144
145             return builder;
146         }
147
148         internal override DbExpression AsCqt(DbExpression row, MemberPath outputMember)
149         {
150             DbExpression cqt = null;
151
152             AsCql(
153                 // createRef action
154                 (refScopeEntitySet, keyMemberOutputPaths) =>
155                 {
156                     // Construct a scoped reference: CreateRef(CPerson1Set, NewRow(pid1, pid2), CPerson1)
157                     EntityType refEntityType = (EntityType)(((RefType)outputMember.EdmType).ElementType);
158                     cqt = refScopeEntitySet.CreateRef(
159                         refEntityType,
160                         keyMemberOutputPaths.Select(km => row.Property(km.CqlFieldAlias)));
161                 },
162                 // createType action
163                 (membersOutputPaths) =>
164                 {
165                     // Construct an entity/complex/Association type in the Members order for fields: CPerson(CPerson1_Pid, CPerson1_Name)
166                     cqt = TypeUsage.Create(m_edmType).New(
167                         membersOutputPaths.Select(m => row.Property(m.CqlFieldAlias)));
168                 },
169                 outputMember);
170
171             return cqt;
172         }
173
174         /// <summary>
175         /// Given the <paramref name="outputMember"/> in the output extent view, generates a constructor expression for
176         /// <paramref name="outputMember"/>'s type, i.e, an expression of the form "Type(....)"
177         /// If <paramref name="outputMember"/> is an association end then instead of constructing an Entity or Complex type, constructs a reference.
178         /// </summary>
179         private void AsCql(Action<EntitySet, IList<MemberPath>> createRef, Action<IList<MemberPath>> createType, MemberPath outputMember)
180         {
181             EntitySet refScopeEntitySet = outputMember.GetScopeOfRelationEnd();
182             if (refScopeEntitySet != null)
183             {
184                 // Construct a scoped reference: CreateRef(CPerson1Set, NewRow(pid1, pid2), CPerson1)
185                 EntityType entityType = refScopeEntitySet.ElementType;
186                 List<MemberPath> keyMemberOutputPaths = new List<MemberPath>(entityType.KeyMembers.Select(km => new MemberPath(outputMember, km)));
187                 createRef(refScopeEntitySet, keyMemberOutputPaths);
188             }
189             else
190             {
191                 // Construct an entity/complex/Association type in the Members order for fields: CPerson(CPerson1_Pid, CPerson1_Name)
192                 Debug.Assert(m_edmType is StructuralType, "m_edmType must be a structural type.");
193                 List<MemberPath> memberOutputPaths = new List<MemberPath>();
194                 foreach (EdmMember structuralMember in Helper.GetAllStructuralMembers(m_edmType))
195                 {
196                     memberOutputPaths.Add(new MemberPath(outputMember, structuralMember));
197                 }
198                 createType(memberOutputPaths);
199             }
200         }
201
202         internal override string ToUserString()
203         {
204             StringBuilder builder = new StringBuilder();
205             ToCompactString(builder);
206             return builder.ToString();
207         }
208
209         internal override void ToCompactString(StringBuilder builder)
210         {
211             builder.Append(m_edmType.Name);
212         }
213         #endregion
214     }
215 }