1
//---------------------------------------------------------------------
2 // <copyright file="FunctionImportMapping.ReturnTypeRanameMapping.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
11 using System
.Collections
.Generic
;
14 using System
.Data
.Metadata
.Edm
;
15 using System
.Data
.Common
.Utils
;
17 using System
.Collections
.ObjectModel
;
18 using System
.Diagnostics
;
20 namespace System
.Data
.Mapping
22 internal abstract class FunctionImportStructuralTypeMapping
24 internal readonly LineInfo LineInfo
;
25 internal readonly Collection
<FunctionImportReturnTypePropertyMapping
> ColumnsRenameList
;
27 internal FunctionImportStructuralTypeMapping(Collection
<FunctionImportReturnTypePropertyMapping
> columnsRenameList
, LineInfo lineInfo
)
29 this.ColumnsRenameList
= columnsRenameList
;
30 this.LineInfo
= lineInfo
;
34 internal sealed class FunctionImportEntityTypeMapping
: FunctionImportStructuralTypeMapping
36 internal FunctionImportEntityTypeMapping(IEnumerable
<EntityType
> isOfTypeEntityTypes
,
37 IEnumerable
<EntityType
> entityTypes
, IEnumerable
<FunctionImportEntityTypeMappingCondition
> conditions
,
38 Collection
<FunctionImportReturnTypePropertyMapping
> columnsRenameList
,
40 : base(columnsRenameList
, lineInfo
)
42 this.IsOfTypeEntityTypes
= new ReadOnlyCollection
<EntityType
>(
43 EntityUtil
.CheckArgumentNull(isOfTypeEntityTypes
, "isOfTypeEntityTypes").ToList());
44 this.EntityTypes
= new ReadOnlyCollection
<EntityType
>(
45 EntityUtil
.CheckArgumentNull(entityTypes
, "entityTypes").ToList());
46 this.Conditions
= new ReadOnlyCollection
<FunctionImportEntityTypeMappingCondition
>(
47 EntityUtil
.CheckArgumentNull(conditions
, "conditions").ToList());
50 internal readonly ReadOnlyCollection
<FunctionImportEntityTypeMappingCondition
> Conditions
;
51 internal readonly ReadOnlyCollection
<EntityType
> EntityTypes
;
52 internal readonly ReadOnlyCollection
<EntityType
> IsOfTypeEntityTypes
;
55 /// Gets all (concrete) entity types implied by this type mapping.
57 internal IEnumerable
<EntityType
> GetMappedEntityTypes(ItemCollection itemCollection
)
59 const bool includeAbstractTypes
= false;
60 return this.EntityTypes
.Concat(
61 this.IsOfTypeEntityTypes
.SelectMany(entityType
=>
62 MetadataHelper
.GetTypeAndSubtypesOf(entityType
, itemCollection
, includeAbstractTypes
)
63 .Cast
<EntityType
>()));
66 internal IEnumerable
<String
> GetDiscriminatorColumns()
68 return this.Conditions
.Select(condition
=> condition
.ColumnName
);
72 internal sealed class FunctionImportComplexTypeMapping
: FunctionImportStructuralTypeMapping
74 internal readonly ComplexType ReturnType
;
76 internal FunctionImportComplexTypeMapping(ComplexType returnType
, Collection
<FunctionImportReturnTypePropertyMapping
> columnsRenameList
, LineInfo lineInfo
)
77 : base(columnsRenameList
, lineInfo
)
79 this.ReturnType
= returnType
;
83 internal abstract class FunctionImportReturnTypePropertyMapping
85 internal readonly string CMember
;
86 internal readonly string SColumn
;
87 internal readonly LineInfo LineInfo
;
89 internal FunctionImportReturnTypePropertyMapping(string cMember
, string sColumn
, LineInfo lineInfo
)
91 this.CMember
= cMember
;
92 this.SColumn
= sColumn
;
93 this.LineInfo
= lineInfo
;
97 internal sealed class FunctionImportReturnTypeScalarPropertyMapping
: FunctionImportReturnTypePropertyMapping
99 internal FunctionImportReturnTypeScalarPropertyMapping(string cMember
, string sColumn
, LineInfo lineInfo
)
100 : base(cMember
, sColumn
, lineInfo
)
106 /// extract the column rename info from polymorphic entity type mappings
108 internal sealed class FunctionImportReturnTypeEntityTypeColumnsRenameBuilder
111 /// CMember -> SMember*
113 internal Dictionary
<string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping
> ColumnRenameMapping
;
115 internal FunctionImportReturnTypeEntityTypeColumnsRenameBuilder(
116 Dictionary
<EntityType
, Collection
<FunctionImportReturnTypePropertyMapping
>> isOfTypeEntityTypeColumnsRenameMapping
,
117 Dictionary
<EntityType
, Collection
<FunctionImportReturnTypePropertyMapping
>> entityTypeColumnsRenameMapping
)
119 EntityUtil
.CheckArgumentNull(isOfTypeEntityTypeColumnsRenameMapping
, "isOfTypeEntityTypeColumnsRenameMapping");
120 EntityUtil
.CheckArgumentNull(entityTypeColumnsRenameMapping
, "entityTypeColumnsRenameMapping");
122 this.ColumnRenameMapping
= new Dictionary
<string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping
>();
124 // Assign the columns renameMapping to the result dictionary.
125 foreach (EntityType entityType
in isOfTypeEntityTypeColumnsRenameMapping
.Keys
)
127 this.SetStructuralTypeColumnsRename(
128 entityType
, isOfTypeEntityTypeColumnsRenameMapping
[entityType
], true/*isTypeOf*/);
131 foreach (EntityType entityType
in entityTypeColumnsRenameMapping
.Keys
)
133 this.SetStructuralTypeColumnsRename(
134 entityType
, entityTypeColumnsRenameMapping
[entityType
], false/*isTypeOf*/);
139 /// Set the column mappings for each defaultMemberName.
141 private void SetStructuralTypeColumnsRename(
142 EntityType entityType
,
143 Collection
<FunctionImportReturnTypePropertyMapping
> columnsRenameMapping
,
146 EntityUtil
.CheckArgumentNull(entityType
, "entityType");
147 EntityUtil
.CheckArgumentNull(columnsRenameMapping
, "columnsRenameMapping");
149 foreach (var mapping
in columnsRenameMapping
)
151 if (!this.ColumnRenameMapping
.Keys
.Contains(mapping
.CMember
))
153 this.ColumnRenameMapping
[mapping
.CMember
] = new FunctionImportReturnTypeStructuralTypeColumnRenameMapping(mapping
.CMember
);
155 this.ColumnRenameMapping
[mapping
.CMember
].AddRename(new FunctionImportReturnTypeStructuralTypeColumn(mapping
.SColumn
, entityType
, isTypeOf
, mapping
.LineInfo
));
160 internal sealed class FunctionImportReturnTypeStructuralTypeColumn
162 internal readonly StructuralType Type
;
163 internal readonly bool IsTypeOf
;
164 internal readonly string ColumnName
;
165 internal readonly LineInfo LineInfo
;
167 internal FunctionImportReturnTypeStructuralTypeColumn(string columnName
, StructuralType type
, bool isTypeOf
, LineInfo lineInfo
)
169 this.ColumnName
= columnName
;
170 this.IsTypeOf
= isTypeOf
;
172 this.LineInfo
= lineInfo
;
176 internal class FunctionImportReturnTypeStructuralTypeColumnRenameMapping
178 private Collection
<FunctionImportReturnTypeStructuralTypeColumn
> _columnListForType
;
179 private Collection
<FunctionImportReturnTypeStructuralTypeColumn
> _columnListForIsTypeOfType
;
181 /// Null if default mapping is not allowed.
183 private readonly string _defaultMemberName
;
184 private Memoizer
<StructuralType
, FunctionImportReturnTypeStructuralTypeColumn
> _renameCache
;
186 internal FunctionImportReturnTypeStructuralTypeColumnRenameMapping(string defaultMemberName
)
188 this._defaultMemberName
= defaultMemberName
;
189 this._columnListForType
= new Collection
<FunctionImportReturnTypeStructuralTypeColumn
>();
190 this._columnListForIsTypeOfType
= new Collection
<FunctionImportReturnTypeStructuralTypeColumn
>();
191 this._renameCache
= new Memoizer
<StructuralType
, FunctionImportReturnTypeStructuralTypeColumn
>(
192 this.GetRename
, EqualityComparer
<StructuralType
>.Default
);
196 /// <see cref="GetRename(EdmType, out IXmlLineInfo)"/> for more info.
198 internal string GetRename(EdmType type
)
200 IXmlLineInfo lineInfo
;
201 return GetRename(type
, out lineInfo
);
205 /// A default mapping (property "Foo" maps by convention to column "Foo"), if allowed, has the lowest precedence.
206 /// A mapping for a specific type (EntityType="Bar") takes precedence over a mapping for a hierarchy (EntityType="IsTypeOf(Bar)"))
207 /// If there are two hierarchy mappings, the most specific mapping takes precedence.
208 /// For instance, given the types Base, Derived1 : Base, and Derived2 : Derived1,
209 /// w.r.t. Derived1 "IsTypeOf(Derived1)" takes precedence over "IsTypeOf(Base)" when you ask for the rename of Derived1
211 /// <param name="lineInfo">Empty for default rename mapping.</param>
212 internal string GetRename(EdmType type
, out IXmlLineInfo lineInfo
)
214 Debug
.Assert(type
is StructuralType
, "we can only rename structural type");
215 EntityUtil
.CheckArgumentNull(type
, "type");
217 var rename
= this._renameCache
.Evaluate(type
as StructuralType
);
218 lineInfo
= rename
.LineInfo
;
219 return rename
.ColumnName
;
222 private FunctionImportReturnTypeStructuralTypeColumn
GetRename(StructuralType typeForRename
)
224 FunctionImportReturnTypeStructuralTypeColumn ofTypecolumn
= _columnListForType
.FirstOrDefault(t
=> t
.Type
== typeForRename
);
225 if (null != ofTypecolumn
)
230 // if there are duplicate istypeof mapping defined rename for the same column, the last one wins
231 FunctionImportReturnTypeStructuralTypeColumn isOfTypeColumn
= _columnListForIsTypeOfType
.Where(t
=> t
.Type
== typeForRename
).LastOrDefault();
233 if (null != isOfTypeColumn
)
235 return isOfTypeColumn
;
239 // find out all the tyes that is isparent type of this lookup type
240 IEnumerable
<FunctionImportReturnTypeStructuralTypeColumn
> nodesInBaseHierachy
=
241 _columnListForIsTypeOfType
.Where(t
=> t
.Type
.IsAssignableFrom(typeForRename
));
243 if (nodesInBaseHierachy
.Count() == 0)
245 // non of its parent is renamed, so it will take the default one
246 return new FunctionImportReturnTypeStructuralTypeColumn(this._defaultMemberName
, typeForRename
, false, null);
250 // we will guarantee that there will be some mapping for us on this column
251 // find out which one is lowest on the link
252 return GetLowestParentInHierachy(nodesInBaseHierachy
);
257 private FunctionImportReturnTypeStructuralTypeColumn
GetLowestParentInHierachy(IEnumerable
<FunctionImportReturnTypeStructuralTypeColumn
> nodesInHierachy
)
259 FunctionImportReturnTypeStructuralTypeColumn lowestParent
= null;
260 foreach (var node
in nodesInHierachy
)
262 if (lowestParent
== null)
266 else if (lowestParent
.Type
.IsAssignableFrom(node
.Type
))
271 Debug
.Assert(null != lowestParent
, "We should have the lowest parent");
275 internal void AddRename(FunctionImportReturnTypeStructuralTypeColumn renamedColumn
)
277 EntityUtil
.CheckArgumentNull(renamedColumn
, "renamedColumn");
279 if (!renamedColumn
.IsTypeOf
)
281 // add to collection if the mapping is for specific type
282 this._columnListForType
.Add(renamedColumn
);
286 _columnListForIsTypeOfType
.Add(renamedColumn
);