Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Metadata / Converter.cs
1 //---------------------------------------------------------------------
2 // <copyright file="Converter.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.Collections.Generic;
11 using System.Data.Common;
12 using System.Data.Objects.DataClasses;
13 using System.Diagnostics;
14 using System.Globalization;
15 using System.Linq;
16 using Som = System.Data.EntityModel.SchemaObjectModel;
17
18 namespace System.Data.Metadata.Edm
19 {
20     /// <summary>
21     /// Helper Class for converting SOM objects to metadata objects
22     /// This class should go away once we have completely integrated SOM and metadata
23     /// </summary>
24     internal static class Converter
25     {
26         #region Constructor
27         /// <summary>
28         /// Static constructor for creating FacetDescription objects that we use
29         /// </summary>
30         static Converter()
31         {
32             Debug.Assert(Enum.GetUnderlyingType(typeof(ConcurrencyMode)) == typeof(int), "Please update underlying type below accordingly.");
33
34             // Create the enum types that we will need
35             EnumType concurrencyModeType = new EnumType(EdmProviderManifest.ConcurrencyModeFacetName,
36                                                         EdmConstants.EdmNamespace,
37                                                         underlyingType: PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32),
38                                                         isFlags: false,
39                                                         dataSpace: DataSpace.CSpace);
40
41             foreach (string name in Enum.GetNames(typeof(ConcurrencyMode)))
42             {
43                 concurrencyModeType.AddMember(
44                     new EnumMember(
45                         name,
46                         (int)Enum.Parse(typeof(ConcurrencyMode), name, false)));
47             }
48
49             Debug.Assert(Enum.GetUnderlyingType(typeof(StoreGeneratedPattern)) == typeof(int), "Please update underlying type below accordingly.");
50
51             EnumType storeGeneratedPatternType = new EnumType(EdmProviderManifest.StoreGeneratedPatternFacetName,
52                                                               EdmConstants.EdmNamespace,
53                                                               underlyingType: PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32),
54                                                               isFlags: false,
55                                                               dataSpace: DataSpace.CSpace);
56
57             foreach (string name in Enum.GetNames(typeof(StoreGeneratedPattern)))
58             {
59                 storeGeneratedPatternType.AddMember(
60                     new EnumMember(
61                         name,
62                         (int)Enum.Parse(typeof(StoreGeneratedPattern), name, false)));
63             }
64
65
66             // Now create the facet description objects
67             ConcurrencyModeFacet = new FacetDescription(EdmProviderManifest.ConcurrencyModeFacetName,
68                                                         concurrencyModeType,
69                                                         null,
70                                                         null,
71                                                         ConcurrencyMode.None);
72             StoreGeneratedPatternFacet = new FacetDescription(EdmProviderManifest.StoreGeneratedPatternFacetName,
73                                                               storeGeneratedPatternType,
74                                                               null,
75                                                               null,
76                                                               StoreGeneratedPattern.None);
77             CollationFacet = new FacetDescription(EdmProviderManifest.CollationFacetName,
78                                                   MetadataItem.EdmProviderManifest.GetPrimitiveType(PrimitiveTypeKind.String),
79                                                   null,
80                                                   null,
81                                                   string.Empty);
82         }
83         #endregion
84
85         #region Fields
86         internal static readonly FacetDescription ConcurrencyModeFacet;
87         internal static readonly FacetDescription StoreGeneratedPatternFacet;
88         internal static readonly FacetDescription CollationFacet;
89
90         #endregion
91
92         #region Methods
93         /// <summary>
94         /// Converts a schema from SOM into Metadata
95         /// </summary>
96         /// <param name="somSchema">The SOM schema to convert</param>
97         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
98         /// <param name="itemCollection">The item collection for currently existing metadata objects</param>
99         internal static IEnumerable<GlobalItem> ConvertSchema(Som.Schema somSchema,
100                                                               DbProviderManifest providerManifest,
101                                                               ItemCollection itemCollection)
102         {
103             Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems = new Dictionary<Som.SchemaElement, GlobalItem>();
104             ConvertSchema(somSchema, providerManifest, new ConversionCache(itemCollection), newGlobalItems);
105             return newGlobalItems.Values;
106         }
107
108         internal static IEnumerable<GlobalItem> ConvertSchema(IList<Som.Schema> somSchemas,
109                                                               DbProviderManifest providerManifest,
110                                                               ItemCollection itemCollection)
111         {
112             Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems = new Dictionary<Som.SchemaElement, GlobalItem>();
113             ConversionCache conversionCache = new ConversionCache(itemCollection);
114
115             foreach (Som.Schema somSchema in somSchemas)
116             {
117                 ConvertSchema(somSchema, providerManifest, conversionCache, newGlobalItems);
118             }
119
120             return newGlobalItems.Values;
121         }
122
123         private static void ConvertSchema(Som.Schema somSchema, DbProviderManifest providerManifest,
124             ConversionCache convertedItemCache, Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
125         {
126             List<Som.Function> funcsWithUnresolvedTypes = new List<Som.Function>();
127             foreach (Som.SchemaType element in somSchema.SchemaTypes)
128             {
129                 if (null == LoadSchemaElement(element, providerManifest, convertedItemCache, newGlobalItems))
130                 {
131                     if (element is Som.Function)
132                     {
133                         funcsWithUnresolvedTypes.Add(element as Som.Function);
134                     }
135                 }
136             }
137
138             foreach (Som.SchemaEntityType element in somSchema.SchemaTypes.OfType<Som.SchemaEntityType>())
139             {
140                 LoadEntityTypePhase2(element, providerManifest, convertedItemCache, newGlobalItems);
141             }
142
143             foreach (var function in funcsWithUnresolvedTypes)
144             {
145                 if (null == LoadSchemaElement(function, providerManifest, convertedItemCache, newGlobalItems))
146                 {
147                     Debug.Fail("Could not load model function definition"); //this should never happen.
148                 }
149             }
150
151             if (convertedItemCache.ItemCollection.DataSpace == DataSpace.CSpace)
152             {
153                 EdmItemCollection edmCollection = (EdmItemCollection)convertedItemCache.ItemCollection;
154                 edmCollection.EdmVersion = somSchema.SchemaVersion;
155             }
156             else
157             {
158                 Debug.Assert(convertedItemCache.ItemCollection.DataSpace == DataSpace.SSpace, "Did you add a new space?");
159                 // when converting the ProviderManifest, the DataSpace is SSpace, but the ItemCollection is EmptyItemCollection, 
160                 // not StoreItemCollection
161                 StoreItemCollection storeCollection = convertedItemCache.ItemCollection as StoreItemCollection;
162                 if (storeCollection != null)
163                 {
164                     storeCollection.StoreSchemaVersion = somSchema.SchemaVersion;
165                 }
166             }
167         }
168
169         /// <summary>
170         /// Loads a schema element
171         /// </summary>
172         /// <param name="element">The SOM element to process</param>
173         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
174         /// <param name="convertedItemCache">The item collection for currently existing metadata objects</param>
175         /// <param name="newGlobalItems">The new GlobalItem objects that are created as a result of this conversion</param>
176         /// <returns>The item resulting from the load</returns>
177         internal static MetadataItem LoadSchemaElement(Som.SchemaType element,
178                                               DbProviderManifest providerManifest,
179                                               ConversionCache convertedItemCache,
180                                               Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
181         {
182             Debug.Assert(providerManifest != null, "This will make the dataspace to be default SSpace");
183             // Try to fetch from the collection first
184             GlobalItem item;
185
186             Debug.Assert(!convertedItemCache.ItemCollection.TryGetValue(element.FQName, false, out item), "Som should have checked for duplicate items");
187
188             // Try to fetch in our collection of new GlobalItems
189             if (newGlobalItems.TryGetValue(element, out item))
190             {
191                 return item;
192             }
193
194             Som.EntityContainer entityContainer = element as Som.EntityContainer;
195             // Perform different conversion depending on the type of the SOM object
196             if (entityContainer != null)
197             {
198                 item = ConvertToEntityContainer(entityContainer,
199                                                 providerManifest,
200                                                 convertedItemCache,
201                                                 newGlobalItems);
202             }
203             else if (element is Som.SchemaEntityType)
204             {
205                 item = ConvertToEntityType((Som.SchemaEntityType)element,
206                                            providerManifest,
207                                            convertedItemCache,
208                                            newGlobalItems);
209             }
210             else if (element is Som.Relationship)
211             {
212                 item = ConvertToAssociationType((Som.Relationship)element,
213                                                 providerManifest,
214                                                 convertedItemCache,
215                                                 newGlobalItems);
216             }
217             else if (element is Som.SchemaComplexType)
218             {
219                 item = ConvertToComplexType((Som.SchemaComplexType)element,
220                                             providerManifest,
221                                             convertedItemCache,
222                                             newGlobalItems);
223             }
224             else if (element is Som.Function)
225             {
226                 item = ConvertToFunction((Som.Function)element, providerManifest,
227                     convertedItemCache, null, newGlobalItems);
228             }
229             else if (element is Som.SchemaEnumType)
230             {
231                 item = ConvertToEnumType((Som.SchemaEnumType)element, newGlobalItems);
232             }
233             else
234             {
235                 // the only type we don't handle is the ProviderManifest TypeElement
236                 // if it is anything else, it is probably a mistake
237                 Debug.Assert(element is Som.TypeElement &&
238                     element.Schema.DataModel == Som.SchemaDataModelOption.ProviderManifestModel,
239                     "Unknown Type in somschema");
240                 return null;
241             }
242
243             return item;
244         }
245
246         /// <summary>
247         /// Converts an entity container from SOM to metadata
248         /// </summary>
249         /// <param name="element">The SOM element to process</param>
250         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
251         /// <param name="convertedItemCache">The item collection for currently existing metadata objects</param>
252         /// <param name="newGlobalItems">The new GlobalItem objects that are created as a result of this conversion</param>
253         /// <returns>The entity container object resulting from the convert</returns>
254         private static EntityContainer ConvertToEntityContainer(Som.EntityContainer element,
255                                                                 DbProviderManifest providerManifest,
256                                                                 ConversionCache convertedItemCache,
257                                                                 Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
258         {
259             // Creating a new entity container object and populate with converted entity set objects
260             EntityContainer entityContainer = new EntityContainer(element.Name, GetDataSpace(providerManifest));
261             newGlobalItems.Add(element, entityContainer);
262
263             foreach (Som.EntityContainerEntitySet entitySet in element.EntitySets)
264             {
265                 entityContainer.AddEntitySetBase(ConvertToEntitySet(entitySet,
266                                                                       entityContainer.Name,
267                                                                       providerManifest,
268                                                                       convertedItemCache,
269                                                                       newGlobalItems));
270             }
271
272             // Populate with converted relationship set objects
273             foreach (Som.EntityContainerRelationshipSet relationshipSet in element.RelationshipSets)
274             {
275                 Debug.Assert(relationshipSet.Relationship.RelationshipKind == RelationshipKind.Association,
276                              "We do not support containment set");
277
278                 entityContainer.AddEntitySetBase(ConvertToAssociationSet(relationshipSet,
279                                                                            providerManifest,
280                                                                            convertedItemCache,
281                                                                            entityContainer,
282                                                                            newGlobalItems));
283             }
284
285             // Populate with converted function imports
286             foreach (Som.Function functionImport in element.FunctionImports)
287             {
288                 entityContainer.AddFunctionImport(ConvertToFunction(functionImport,
289                     providerManifest, convertedItemCache, entityContainer, newGlobalItems));
290             }
291
292             // Extract the optional Documentation
293             if (element.Documentation != null)
294             {
295                 entityContainer.Documentation = ConvertToDocumentation(element.Documentation);
296             }
297
298             AddOtherContent(element, entityContainer);
299
300             return entityContainer;
301         }
302
303         /// <summary>
304         /// Converts an entity type from SOM to metadata
305         /// 
306         /// This method should only build the internally contained and vertical part of the EntityType (keys, properties, and base types) but not 
307         /// sideways parts (NavigationProperties) that go between types or we risk trying to access and EntityTypes keys, from the referential constraint,
308         /// before the base type, which has the keys, is setup yet.
309         /// </summary>
310         /// <param name="element">The SOM element to process</param>
311         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
312         /// <param name="convertedItemCache">The item collection for currently existing metadata objects</param>
313         /// <param name="newGlobalItems">The new GlobalItem objects that are created as a result of this conversion</param>
314         /// <returns>The entity type object resulting from the convert</returns>
315         private static EntityType ConvertToEntityType(Som.SchemaEntityType element,
316                                                       DbProviderManifest providerManifest,
317                                                       ConversionCache convertedItemCache,
318                                                       Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
319         {
320             string[] keyMembers = null;
321             // Check if this type has keys
322             if (element.DeclaredKeyProperties.Count != 0)
323             {
324                 keyMembers = new string[element.DeclaredKeyProperties.Count];
325                 for (int i = 0; i < keyMembers.Length; i++)
326                 {
327                     //Add the name of the key property to the list of
328                     //key properties
329                     keyMembers[i] = (element.DeclaredKeyProperties[i].Property.Name);
330                 }
331             }
332
333             EdmProperty[] properties = new EdmProperty[element.Properties.Count];
334             int index = 0;
335
336             foreach (Som.StructuredProperty somProperty in element.Properties)
337             {
338                 properties[index++] = ConvertToProperty(somProperty,
339                                                         providerManifest,
340                                                         convertedItemCache,
341                                                         newGlobalItems);
342             }
343
344             EntityType entityType = new EntityType(element.Name,
345                                                    element.Namespace,
346                                                    GetDataSpace(providerManifest),
347                                                    keyMembers,
348                                                    properties);
349
350             if (element.BaseType != null)
351             {
352                 entityType.BaseType = (EdmType)(LoadSchemaElement(element.BaseType,
353                                                                   providerManifest,
354                                                                   convertedItemCache,
355                                                                   newGlobalItems));
356             }
357
358             // set the abstract and sealed type values for the entity type
359             entityType.Abstract = element.IsAbstract;
360             // Extract the optional Documentation
361             if (element.Documentation != null)
362             {
363                 entityType.Documentation = ConvertToDocumentation(element.Documentation);
364             }
365             AddOtherContent(element, entityType);
366             newGlobalItems.Add(element, entityType);
367             return entityType;
368         }
369
370         private static void LoadEntityTypePhase2(Som.SchemaEntityType element,
371                                                       DbProviderManifest providerManifest,
372                                                       ConversionCache convertedItemCache,
373                                                       Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
374         {
375             EntityType entityType = (EntityType)newGlobalItems[element];
376
377             // Since Navigation properties are internal and not part of member collection, we
378             // need to initialize the base class first before we start adding the navigation property
379             // this will ensure that all the base navigation properties are initialized
380             foreach (Som.NavigationProperty somNavigationProperty in element.NavigationProperties)
381             {
382                 entityType.AddMember(ConvertToNavigationProperty(entityType,
383                                                                  somNavigationProperty,
384                                                                  providerManifest,
385                                                                  convertedItemCache,
386                                                                  newGlobalItems));
387             }
388         }
389
390         /// <summary>
391         /// Converts an complex type from SOM to metadata
392         /// </summary>
393         /// <param name="element">The SOM element to process</param>
394         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
395         /// <param name="convertedItemCache">The item collection for currently existing metadata objects</param>
396         /// <param name="newGlobalItems">The new GlobalItem objects that are created as a result of this conversion</param>
397         /// <returns>The complex type object resulting from the convert</returns>
398         private static ComplexType ConvertToComplexType(Som.SchemaComplexType element,
399                                                         DbProviderManifest providerManifest,
400                                                         ConversionCache convertedItemCache,
401                                                         Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
402         {
403             ComplexType complexType = new ComplexType(element.Name,
404                                                       element.Namespace,
405                                                       GetDataSpace(providerManifest));
406             newGlobalItems.Add(element, complexType);
407
408             foreach (Som.StructuredProperty somProperty in element.Properties)
409             {
410                 complexType.AddMember(ConvertToProperty(somProperty,
411                                                           providerManifest,
412                                                           convertedItemCache,
413                                                           newGlobalItems));
414             }
415
416             // set the abstract and sealed type values for the entity type
417             complexType.Abstract = element.IsAbstract;
418
419             if (element.BaseType != null)
420             {
421                 complexType.BaseType = (EdmType)(LoadSchemaElement(element.BaseType,
422                                                                   providerManifest,
423                                                                   convertedItemCache,
424                                                                   newGlobalItems));
425             }
426
427             // Extract the optional Documentation
428             if (element.Documentation != null)
429             {
430                 complexType.Documentation = ConvertToDocumentation(element.Documentation);
431             }
432             AddOtherContent(element, complexType);
433
434             return complexType;
435         }
436
437         /// <summary>
438         /// Converts an association type from SOM to metadata
439         /// </summary>
440         /// <param name="element">The SOM element to process</param>
441         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
442         /// <param name="convertedItemCache">The item collection for currently existing metadata objects</param>
443         /// <param name="newGlobalItems">The new GlobalItem objects that are created as a result of this conversion</param>
444         /// <returns>The association type object resulting from the convert</returns>
445         private static AssociationType ConvertToAssociationType(Som.Relationship element,
446                                                                 DbProviderManifest providerManifest,
447                                                                 ConversionCache convertedItemCache,
448                                                                 Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
449         {
450             Debug.Assert(element.RelationshipKind == RelationshipKind.Association);
451
452             AssociationType associationType = new AssociationType(element.Name,
453                                                                   element.Namespace,
454                                                                   element.IsForeignKey,
455                                                                   GetDataSpace(providerManifest));
456             newGlobalItems.Add(element, associationType);
457
458             foreach (Som.RelationshipEnd end in element.Ends)
459             {
460                 Som.SchemaType entityTypeElement = end.Type;
461                 EntityType endEntityType = (EntityType)LoadSchemaElement(entityTypeElement,
462                                                                 providerManifest,
463                                                                 convertedItemCache,
464                                                                 newGlobalItems);
465
466                 AssociationEndMember endMember = InitializeAssociationEndMember(associationType, end, endEntityType);
467                 AddOtherContent(end, endMember);
468                 // Loop through and convert the operations
469                 foreach (Som.OnOperation operation in end.Operations)
470                 {
471                     // Process only the ones that we recognize
472                     if (operation.Operation != Som.Operation.Delete)
473                     {
474                         continue;
475                     }
476
477                     // Determine the action for this operation
478                     OperationAction action = OperationAction.None;
479                     switch (operation.Action)
480                     {
481                         case Som.Action.Cascade:
482                             action = OperationAction.Cascade;
483                             break;
484                         case Som.Action.None:
485                             action = OperationAction.None;
486                             break;
487                         default:
488                             Debug.Fail("Operation action not supported.");
489                             break;
490                     }
491                     endMember.DeleteBehavior = action;
492                 }
493
494                 // Extract optional Documentation from the end element
495                 if (end.Documentation != null)
496                 {
497                     endMember.Documentation = ConvertToDocumentation(end.Documentation);
498                 }
499             }
500
501             Debug.Assert(associationType.ReferentialConstraints.Count == 0, "This must never have been initialized");
502
503             for (int i = 0; i < element.Constraints.Count; i++)
504             {
505                 Som.ReferentialConstraint constraint = element.Constraints[i];
506                 AssociationEndMember fromMember = (AssociationEndMember)associationType.Members[constraint.PrincipalRole.Name];
507                 AssociationEndMember toMember = (AssociationEndMember)associationType.Members[constraint.DependentRole.Name];
508                 EntityTypeBase fromEntityType = ((RefType)fromMember.TypeUsage.EdmType).ElementType;
509                 EntityTypeBase toEntityType = ((RefType)toMember.TypeUsage.EdmType).ElementType;
510
511                 ReferentialConstraint referentialConstraint = new ReferentialConstraint(fromMember, toMember,
512                                                                                         GetProperties(fromEntityType, constraint.PrincipalRole.RoleProperties),
513                                                                                         GetProperties(toEntityType, constraint.DependentRole.RoleProperties));
514
515                 // Attach the optional Documentation
516                 if (constraint.Documentation != null)
517                     referentialConstraint.Documentation = ConvertToDocumentation(constraint.Documentation);
518                 if (constraint.PrincipalRole.Documentation != null)
519                     referentialConstraint.FromRole.Documentation = ConvertToDocumentation(constraint.PrincipalRole.Documentation);
520                 if (constraint.DependentRole.Documentation != null)
521                     referentialConstraint.ToRole.Documentation = ConvertToDocumentation(constraint.DependentRole.Documentation);
522
523
524                 associationType.AddReferentialConstraint(referentialConstraint);
525                 AddOtherContent(element.Constraints[i], referentialConstraint);
526
527             }
528
529             // Extract the optional Documentation
530             if (element.Documentation != null)
531             {
532                 associationType.Documentation = ConvertToDocumentation(element.Documentation);
533             }
534             AddOtherContent(element, associationType);
535
536             return associationType;
537         }
538
539         /// <summary>
540         /// Initialize the end member if its not initialized already
541         /// </summary>
542         /// <param name="associationType"></param>
543         /// <param name="end"></param>
544         /// <param name="endMemberType"></param>
545         private static AssociationEndMember InitializeAssociationEndMember(AssociationType associationType, Som.IRelationshipEnd end,
546             EntityType endMemberType)
547         {
548             AssociationEndMember associationEnd;
549
550             EdmMember member;
551             // make sure that the end is not initialized as of yet
552             if (!associationType.Members.TryGetValue(end.Name, false/*ignoreCase*/, out member))
553             {
554                 // Create the end member and add the operations
555                 associationEnd = new AssociationEndMember(end.Name,
556                                                           endMemberType.GetReferenceType(),
557                                                           end.Multiplicity.Value);
558                 associationType.AddKeyMember(associationEnd);
559             }
560             else
561             {
562                 associationEnd = (AssociationEndMember)member;
563             }
564
565             //Extract the optional Documentation
566             Som.RelationshipEnd relationshipEnd = end as Som.RelationshipEnd;
567
568             if (relationshipEnd != null && (relationshipEnd.Documentation != null))
569             {
570                 associationEnd.Documentation = ConvertToDocumentation(relationshipEnd.Documentation);
571             }
572
573             return associationEnd;
574         }
575
576         private static EdmProperty[] GetProperties(EntityTypeBase entityType, IList<Som.PropertyRefElement> properties)
577         {
578             Debug.Assert(properties.Count != 0);
579             EdmProperty[] result = new EdmProperty[properties.Count];
580
581             for (int i = 0; i < properties.Count; i++)
582             {
583                 result[i] = (EdmProperty)entityType.Members[properties[i].Name];
584             }
585
586             return result;
587         }
588
589
590         private static void AddOtherContent(Som.SchemaElement element, MetadataItem item)
591         {
592             if (element.OtherContent.Count > 0)
593             {
594                 item.AddMetadataProperties(element.OtherContent);
595             }
596         }
597
598         /// <summary>
599         /// Converts an entity set from SOM to metadata
600         /// </summary>
601         /// <param name="set">The SOM element to process</param>
602         /// <param name="containerName">the name of the container this will be added to</param>
603         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
604         /// <param name="convertedItemCache">The item collection for currently existing metadata objects</param>
605         /// <param name="newGlobalItems">The new GlobalItem objects that are created as a result of this conversion</param>
606         /// <returns>The entity set object resulting from the convert</returns>
607         private static EntitySet ConvertToEntitySet(Som.EntityContainerEntitySet set,
608                                                     string containerName,
609                                                     DbProviderManifest providerManifest,
610                                                     ConversionCache convertedItemCache,
611                                                     Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
612         {
613             EntitySet entitySet = new EntitySet(set.Name, set.DbSchema, set.Table, set.DefiningQuery,
614                                                  (EntityType)LoadSchemaElement(set.EntityType,
615                                                                                providerManifest,
616                                                                                convertedItemCache,
617                                                                                newGlobalItems));
618
619             // Extract the optional Documentation
620             if (set.Documentation != null)
621             {
622                 entitySet.Documentation = ConvertToDocumentation(set.Documentation);
623             }
624             AddOtherContent(set, entitySet);
625
626             return entitySet;
627         }
628
629         /// <summary>
630         /// Converts an entity set from SOM to metadata
631         /// </summary>
632         /// <param name="set">The SOM element to process</param>
633         /// <param name="container"></param>
634         /// <returns>The entity set object resulting from the convert</returns>
635         private static EntitySet GetEntitySet(Som.EntityContainerEntitySet set, EntityContainer container)
636         {
637             return container.GetEntitySetByName(set.Name, false);
638         }
639
640         /// <summary>
641         /// Converts an association set from SOM to metadata
642         /// </summary>
643         /// <param name="relationshipSet">The SOM element to process</param>
644         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
645         /// <param name="convertedItemCache">The item collection for currently existing metadata objects</param>
646         /// <param name="newGlobalItems">The new GlobalItem objects that are created as a result of this conversion</param>
647         /// <param name="container"></param>
648         /// <returns>The association set object resulting from the convert</returns>
649         private static AssociationSet ConvertToAssociationSet(Som.EntityContainerRelationshipSet relationshipSet,
650                                                               DbProviderManifest providerManifest,
651                                                               ConversionCache convertedItemCache,
652                                                               EntityContainer container,
653                                                               Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
654         {
655             Debug.Assert(relationshipSet.Relationship.RelationshipKind == RelationshipKind.Association);
656
657             AssociationType associationType = (AssociationType)LoadSchemaElement((Som.SchemaType)relationshipSet.Relationship,
658                                                                                   providerManifest,
659                                                                                   convertedItemCache,
660                                                                                   newGlobalItems);
661
662             AssociationSet associationSet = new AssociationSet(relationshipSet.Name, associationType);
663
664             foreach (Som.EntityContainerRelationshipSetEnd end in relationshipSet.Ends)
665             {
666                 //-- need the EntityType for the end
667                 EntityType endEntityType = (EntityType)LoadSchemaElement(end.EntitySet.EntityType,
668                                                                          providerManifest,
669                                                                          convertedItemCache,
670                                                                          newGlobalItems);
671                 //-- need to get the end member
672                 AssociationEndMember endMember = (AssociationEndMember)associationType.Members[end.Name];
673                 //-- create the end
674                 AssociationSetEnd associationSetEnd = new AssociationSetEnd(GetEntitySet(end.EntitySet, container),
675                                                                             associationSet,
676                                                                             endMember);
677
678                 AddOtherContent(end, associationSetEnd);
679                 associationSet.AddAssociationSetEnd(associationSetEnd);
680
681                 // Extract optional Documentation from the end element
682                 if (end.Documentation != null)
683                 {
684                     associationSetEnd.Documentation = ConvertToDocumentation(end.Documentation);
685                 }
686             }
687
688             // Extract the optional Documentation
689             if (relationshipSet.Documentation != null)
690             {
691                 associationSet.Documentation = ConvertToDocumentation(relationshipSet.Documentation);
692             }
693             AddOtherContent(relationshipSet, associationSet);
694
695             return associationSet;
696         }
697
698         /// <summary>
699         /// Converts a property from SOM to metadata
700         /// </summary>
701         /// <param name="somProperty">The SOM element to process</param>
702         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
703         /// <param name="convertedItemCache">The item collection for currently existing metadata objects</param>
704         /// <param name="newGlobalItems">The new GlobalItem objects that are created as a result of this conversion</param>
705         /// <returns>The property object resulting from the convert</returns>
706         private static EdmProperty ConvertToProperty(Som.StructuredProperty somProperty,
707                                                   DbProviderManifest providerManifest,
708                                                   ConversionCache convertedItemCache,
709                                                   Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
710         {
711             EdmProperty property;
712
713             // Get the appropriate type object for this type, for primitive and enum types, get the facet values for the type
714             // property as a type usage object as well                  
715             TypeUsage typeUsage = null;
716
717             Som.ScalarType scalarType = somProperty.Type as Som.ScalarType;
718
719             if (scalarType != null && somProperty.Schema.DataModel != Som.SchemaDataModelOption.EntityDataModel)
720             {
721                 // parsing ssdl
722                 typeUsage = somProperty.TypeUsage;
723                 UpdateSentinelValuesInFacets(ref typeUsage);
724             }
725             else
726             {
727                 EdmType propertyType;
728
729                 if (scalarType != null)
730                 {
731                     Debug.Assert(somProperty.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType);
732                     // try to get the instance of the primitive type from the item collection so that it back pointer is set.
733                     propertyType = convertedItemCache.ItemCollection.GetItem<PrimitiveType>(somProperty.TypeUsage.EdmType.FullName);
734                 }
735                 else
736                 {
737                     propertyType = (EdmType)LoadSchemaElement(somProperty.Type, providerManifest, convertedItemCache, newGlobalItems);
738                 }
739
740                 if (somProperty.CollectionKind != CollectionKind.None)
741                 {
742                     typeUsage = TypeUsage.Create(new CollectionType(propertyType));
743                 }
744                 else
745                 {
746                     Som.SchemaEnumType enumType = scalarType == null ? somProperty.Type as Som.SchemaEnumType : null;
747                     typeUsage = TypeUsage.Create(propertyType);
748                     if (enumType != null)
749                     {
750                         somProperty.EnsureEnumTypeFacets(convertedItemCache, newGlobalItems);
751                     }
752
753                     if (somProperty.TypeUsage != null)
754                     {
755                         ApplyTypePropertyFacets(somProperty.TypeUsage, ref typeUsage);
756                     }
757                 }
758             }
759
760             PopulateGeneralFacets(somProperty, providerManifest, ref typeUsage);
761             property = new EdmProperty(somProperty.Name, typeUsage);
762
763             // Extract the optional Documentation
764             if (somProperty.Documentation != null)
765             {
766                 property.Documentation = ConvertToDocumentation(somProperty.Documentation);
767             }
768             AddOtherContent(somProperty, property);
769
770             return property;
771         }
772
773         /// <summary>
774         /// Converts a navigation property from SOM to metadata
775         /// </summary>
776         /// <param name="declaringEntityType">entity type on which this navigation property was declared</param>
777         /// <param name="somNavigationProperty">The SOM element to process</param>
778         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
779         /// <param name="convertedItemCache">The item collection for currently existing metadata objects</param>
780         /// <param name="newGlobalItems">The new GlobalItem objects that are created as a result of this conversion</param>
781         /// <returns>The property object resulting from the convert</returns>
782         private static NavigationProperty ConvertToNavigationProperty(EntityType declaringEntityType,
783                                                                       Som.NavigationProperty somNavigationProperty,
784                                                                       DbProviderManifest providerManifest,
785                                                                       ConversionCache convertedItemCache,
786                                                                       Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
787         {
788             // Navigation properties cannot be primitive types, so we can ignore the possibility of having primitive type
789             // facets
790             EntityType toEndEntityType = (EntityType)LoadSchemaElement(somNavigationProperty.Type,
791                                                       providerManifest,
792                                                       convertedItemCache,
793                                                       newGlobalItems);
794
795             EdmType edmType = toEndEntityType;
796
797             // Also load the relationship Type that this navigation property represents
798             AssociationType relationshipType = (AssociationType)LoadSchemaElement((Som.Relationship)somNavigationProperty.Relationship,
799                     providerManifest, convertedItemCache, newGlobalItems);
800
801             Som.IRelationshipEnd somRelationshipEnd = null;
802             somNavigationProperty.Relationship.TryGetEnd(somNavigationProperty.ToEnd.Name, out somRelationshipEnd);
803             if (somRelationshipEnd.Multiplicity == RelationshipMultiplicity.Many)
804             {
805                 edmType = toEndEntityType.GetCollectionType();
806             }
807             else
808             {
809                 Debug.Assert(somRelationshipEnd.Multiplicity != RelationshipMultiplicity.Many);
810                 edmType = toEndEntityType;
811             }
812
813             TypeUsage typeUsage;
814             if (somRelationshipEnd.Multiplicity == RelationshipMultiplicity.One)
815             {
816                 typeUsage = TypeUsage.Create(edmType,
817                     new FacetValues { Nullable = false });
818             }
819             else
820             {
821                 typeUsage = TypeUsage.Create(edmType);
822
823             }
824
825             // We need to make sure that both the ends of the relationtype are initialized. If there are not, then we should
826             // initialize them here
827             InitializeAssociationEndMember(relationshipType, somNavigationProperty.ToEnd, toEndEntityType);
828             InitializeAssociationEndMember(relationshipType, somNavigationProperty.FromEnd, declaringEntityType);
829
830             // The type of the navigation property must be a ref or collection depending on which end they belong to
831             NavigationProperty navigationProperty = new NavigationProperty(somNavigationProperty.Name, typeUsage);
832             navigationProperty.RelationshipType = relationshipType;
833             navigationProperty.ToEndMember = (RelationshipEndMember)relationshipType.Members[somNavigationProperty.ToEnd.Name];
834             navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[somNavigationProperty.FromEnd.Name];
835
836             // Extract the optional Documentation
837             if (somNavigationProperty.Documentation != null)
838             {
839                 navigationProperty.Documentation = ConvertToDocumentation(somNavigationProperty.Documentation);
840             }
841             AddOtherContent(somNavigationProperty, navigationProperty);
842
843             return navigationProperty;
844         }
845
846         /// <summary>
847         /// Converts a function from SOM to metadata
848         /// </summary>
849         /// <param name="somFunction">The SOM element to process</param>
850         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
851         /// <param name="convertedItemCache">The item collection for currently existing metadata objects</param>
852         /// <param name="functionImportEntityContainer">For function imports, the entity container including the function declaration</param>
853         /// <param name="newGlobalItems">The new GlobalItem objects that are created as a result of this conversion</param>
854         /// <returns>The function object resulting from the convert</returns>
855         private static EdmFunction ConvertToFunction(Som.Function somFunction,
856                                                   DbProviderManifest providerManifest,
857                                                   ConversionCache convertedItemCache,
858                                                   EntityContainer functionImportEntityContainer,
859                                                   Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
860         {
861             // If we already have it, don't bother converting
862             GlobalItem globalItem = null;
863
864             // if we are converted the function import, we need not check the global items collection,
865             // since the function imports are local to the entity container
866             if (!somFunction.IsFunctionImport && newGlobalItems.TryGetValue(somFunction, out globalItem))
867             {
868                 return (EdmFunction)globalItem;
869             }
870
871             bool areConvertingForProviderManifest = somFunction.Schema.DataModel == Som.SchemaDataModelOption.ProviderManifestModel;
872             List<FunctionParameter> returnParameters = new List<FunctionParameter>();
873             if (somFunction.ReturnTypeList != null)
874             {
875                 int i = 0;
876                 foreach (Som.ReturnType somReturnType in somFunction.ReturnTypeList)
877                 {
878                     TypeUsage returnType = GetFunctionTypeUsage(somFunction is Som.ModelFunction,
879                                                             somFunction,
880                                                             somReturnType,
881                                                             providerManifest,
882                                                             areConvertingForProviderManifest,
883                                                             somReturnType.Type,
884                                                             somReturnType.CollectionKind,
885                                                             somReturnType.IsRefType /*isRefType*/,
886                                                             somFunction,
887                                                             convertedItemCache,
888                                                             newGlobalItems);
889                     if (null != returnType)
890                     {
891                         // Create the return parameter object, need to set the declaring type explicitly on the return parameter
892                         // because we aren't adding it to the members collection
893                         string modifier = i == 0 ? string.Empty : i.ToString(System.Globalization.CultureInfo.InvariantCulture);
894                         i++;
895                         FunctionParameter returnParameter = new FunctionParameter(EdmConstants.ReturnType + modifier, returnType, ParameterMode.ReturnValue);
896                         AddOtherContent(somReturnType, returnParameter);
897                         returnParameters.Add(returnParameter);
898                     }
899                     else
900                     {
901                         return null;
902                     }
903                 }
904             }
905             // this case must be second to avoid calling somFunction.Type when returnTypeList has more than one element.
906             else if (somFunction.Type != null)
907             {
908                 TypeUsage returnType = GetFunctionTypeUsage(somFunction is Som.ModelFunction,
909                                                         somFunction,
910                                                         null,
911                                                         providerManifest,
912                                                         areConvertingForProviderManifest,
913                                                         somFunction.Type,
914                                                         somFunction.CollectionKind,
915                                                         somFunction.IsReturnAttributeReftype /*isRefType*/,
916                                                         somFunction,
917                                                         convertedItemCache,
918                                                         newGlobalItems);
919                 if (null != returnType)
920                 {
921                     // Create the return parameter object, need to set the declaring type explicitly on the return parameter
922                     // because we aren't adding it to the members collection                    
923                     returnParameters.Add(new FunctionParameter(EdmConstants.ReturnType, returnType, ParameterMode.ReturnValue));
924                 }
925                 else
926                 {
927                     //Return type was specified but we could not find a type usage
928                     return null;
929                 }
930             }
931
932             string functionNamespace;
933             EntitySet[] entitySets = null;
934             if (somFunction.IsFunctionImport)
935             {
936                 var somFunctionImport = (Som.FunctionImportElement)somFunction;
937                 functionNamespace = somFunctionImport.Container.Name;
938                 if (null != somFunctionImport.EntitySet)
939                 {
940                     EntityContainer entityContainer;
941                     Debug.Assert(somFunctionImport.ReturnTypeList == null || somFunctionImport.ReturnTypeList.Count == 1,
942                         "EntitySet cannot be specified on a FunctionImport if there are multiple ReturnType children");
943
944                     Debug.Assert(functionImportEntityContainer != null, "functionImportEntityContainer must be specified during function import conversion");
945                     entityContainer = functionImportEntityContainer;
946                     entitySets = new EntitySet[] { GetEntitySet(somFunctionImport.EntitySet, entityContainer) };
947                 }
948                 else if (null != somFunctionImport.ReturnTypeList)
949                 {
950                     Debug.Assert(functionImportEntityContainer != null, "functionImportEntityContainer must be specified during function import conversion");
951                     EntityContainer entityContainer = functionImportEntityContainer;
952                     entitySets = somFunctionImport.ReturnTypeList
953                         .Select(returnType => null != returnType.EntitySet
954                             ? GetEntitySet(returnType.EntitySet, functionImportEntityContainer)
955                             : null)
956                         .ToArray();
957                 }
958             }
959             else
960             {
961                 functionNamespace = somFunction.Namespace;
962             }
963
964             List<FunctionParameter> parameters = new List<FunctionParameter>();
965             foreach (Som.Parameter somParameter in somFunction.Parameters)
966             {
967                 TypeUsage parameterType = GetFunctionTypeUsage(somFunction is Som.ModelFunction,
968                                                                somFunction,
969                                                                somParameter,
970                                                                providerManifest,
971                                                                areConvertingForProviderManifest,
972                                                                somParameter.Type,
973                                                                somParameter.CollectionKind,
974                                                                somParameter.IsRefType,
975                                                                somParameter,
976                                                                convertedItemCache,
977                                                                newGlobalItems);
978                 if (parameterType == null)
979                 {
980                     return null;
981                 }
982
983                 FunctionParameter parameter = new FunctionParameter(somParameter.Name,
984                                                                     parameterType,
985                                                                     GetParameterMode(somParameter.ParameterDirection));
986                 AddOtherContent(somParameter, parameter);
987
988                 if (somParameter.Documentation != null)
989                 {
990                     parameter.Documentation = ConvertToDocumentation(somParameter.Documentation);
991                 }
992                 parameters.Add(parameter);
993             }
994
995             EdmFunction function = new EdmFunction(somFunction.Name,
996                 functionNamespace,
997                 GetDataSpace(providerManifest),
998                 new EdmFunctionPayload
999                 {
1000                     Schema = somFunction.DbSchema,
1001                     StoreFunctionName = somFunction.StoreFunctionName,
1002                     CommandText = somFunction.CommandText,
1003                     EntitySets = entitySets,
1004                     IsAggregate = somFunction.IsAggregate,
1005                     IsBuiltIn = somFunction.IsBuiltIn,
1006                     IsNiladic = somFunction.IsNiladicFunction,
1007                     IsComposable = somFunction.IsComposable,
1008                     IsFromProviderManifest = areConvertingForProviderManifest,
1009                     IsFunctionImport = somFunction.IsFunctionImport,
1010                     ReturnParameters = returnParameters.ToArray(),
1011                     Parameters = parameters.ToArray(),
1012                     ParameterTypeSemantics = somFunction.ParameterTypeSemantics,
1013                 });
1014
1015             // Add this function to new global items, only if it is not a function import
1016             if (!somFunction.IsFunctionImport)
1017             {
1018                 newGlobalItems.Add(somFunction, function);
1019             }
1020
1021             //Check if we already converted functions since we are loading it from 
1022             //ssdl we could see functions many times.
1023             GlobalItem returnFunction = null;
1024             Debug.Assert(!convertedItemCache.ItemCollection.TryGetValue(function.Identity, false, out returnFunction),
1025                 "Function duplicates must be checked by som");
1026
1027             // Extract the optional Documentation
1028             if (somFunction.Documentation != null)
1029             {
1030                 function.Documentation = ConvertToDocumentation(somFunction.Documentation);
1031             }
1032             AddOtherContent(somFunction, function);
1033
1034             return function;
1035         }
1036
1037         /// <summary>
1038         /// Converts SchemaEnumType instance to Metadata EnumType.
1039         /// </summary>
1040         /// <param name="somEnumType">SchemaEnumType to be covnerted.</param>
1041         /// <param name="newGlobalItems">Global item objects where newly created Metadata EnumType will be added.</param>
1042         /// <returns></returns>
1043         private static EnumType ConvertToEnumType(Som.SchemaEnumType somEnumType, Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
1044         {
1045             Debug.Assert(somEnumType != null, "somEnumType != null");
1046             Debug.Assert(newGlobalItems != null, "newGlobalItems != null");
1047             Debug.Assert(somEnumType.UnderlyingType is Som.ScalarType, "At this point the underlying type should have already been validated and should be ScalarType");
1048
1049             Som.ScalarType enumUnderlyingType = (Som.ScalarType)somEnumType.UnderlyingType;
1050
1051             // note that enums don't live in SSpace so there is no need to GetDataSpace() for it.
1052             EnumType enumType = new EnumType(somEnumType.Name,
1053                                              somEnumType.Namespace,
1054                                              enumUnderlyingType.Type,
1055                                              somEnumType.IsFlags,
1056                                              DataSpace.CSpace);
1057
1058             Type clrEnumUnderlyingType = enumUnderlyingType.Type.ClrEquivalentType;
1059
1060             foreach (var somEnumMember in somEnumType.EnumMembers)
1061             {
1062                 Debug.Assert(somEnumMember.Value != null, "value must not be null at this point");
1063                 var enumMember = new EnumMember(somEnumMember.Name, Convert.ChangeType(somEnumMember.Value, clrEnumUnderlyingType, CultureInfo.InvariantCulture));
1064
1065                 if (somEnumMember.Documentation != null)
1066                 {
1067                     enumMember.Documentation = ConvertToDocumentation(somEnumMember.Documentation);
1068                 }
1069
1070                 AddOtherContent(somEnumMember, enumMember);
1071                 enumType.AddMember(enumMember);
1072             }
1073
1074             if (somEnumType.Documentation != null)
1075             {
1076                 enumType.Documentation = ConvertToDocumentation(somEnumType.Documentation);
1077             }
1078             AddOtherContent(somEnumType, enumType);
1079
1080             newGlobalItems.Add(somEnumType, enumType);
1081             return enumType;
1082         }
1083
1084         /// <summary>
1085         /// Converts an SOM Documentation node to a metadata Documentation construct
1086         /// </summary>
1087         /// <param name="element">The SOM element to process</param>
1088         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
1089         /// <param name="convertedItemCache">The item collection for currently existing metadata objects</param>
1090         /// <param name="newGlobalItems">The new GlobalItem objects that are created as a result of this conversion</param>
1091         /// <returns>The Documentation object resulting from the convert operation</returns>
1092         private static Documentation ConvertToDocumentation(Som.DocumentationElement element)
1093         {
1094             Debug.Assert(null != element, "ConvertToDocumentation cannot be invoked with a null Som.Documentation element");
1095             return element.MetadataDocumentation;
1096         }
1097
1098         private static TypeUsage GetFunctionTypeUsage(bool isModelFunction,
1099                                                       Som.Function somFunction,
1100                                                       Som.FacetEnabledSchemaElement somParameter,
1101                                                       DbProviderManifest providerManifest,
1102                                                       bool areConvertingForProviderManifest,
1103                                                       Som.SchemaType type,
1104                                                       CollectionKind collectionKind,
1105                                                       bool isRefType,
1106                                                       Som.SchemaElement schemaElement,
1107                                                       ConversionCache convertedItemCache,
1108                                                       Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
1109         {
1110             if (null != somParameter && areConvertingForProviderManifest
1111                 && somParameter.HasUserDefinedFacets)
1112             {
1113                 return somParameter.TypeUsage;
1114             }
1115
1116             if (null == type)
1117             {
1118                 if (isModelFunction && somParameter != null && somParameter is Som.Parameter)
1119                 {
1120                     ((Som.Parameter)somParameter).ResolveNestedTypeNames(convertedItemCache, newGlobalItems);
1121                     return somParameter.TypeUsage;
1122                 }
1123                 else if (somParameter != null && somParameter is Som.ReturnType)
1124                 {
1125                     ((Som.ReturnType)somParameter).ResolveNestedTypeNames(convertedItemCache, newGlobalItems);
1126                     return somParameter.TypeUsage;
1127                 }
1128                 else
1129                 {
1130                     return null;
1131                 }
1132             }
1133
1134             EdmType edmType;
1135             if (!areConvertingForProviderManifest)
1136             {
1137                 // SOM verifies the type is either scalar, row, or entity
1138                 Som.ScalarType scalarType = type as Som.ScalarType;
1139                 if (null != scalarType)
1140                 {
1141                     if (isModelFunction && somParameter != null)
1142                     {
1143                         if (somParameter.TypeUsage == null)
1144                         {
1145                             somParameter.ValidateAndSetTypeUsage(scalarType);
1146                         }
1147                         return somParameter.TypeUsage;
1148                     }
1149                     else if (isModelFunction)
1150                     {
1151                         Som.ModelFunction modelFunction = somFunction as Som.ModelFunction;
1152                         if (modelFunction.TypeUsage == null)
1153                         {
1154                             modelFunction.ValidateAndSetTypeUsage(scalarType);
1155                         }
1156                         return modelFunction.TypeUsage;
1157                     }
1158                     else if (somParameter != null && somParameter.HasUserDefinedFacets && somFunction.Schema.DataModel == System.Data.EntityModel.SchemaObjectModel.SchemaDataModelOption.ProviderDataModel)
1159                     {
1160                         somParameter.ValidateAndSetTypeUsage(scalarType);
1161                         return somParameter.TypeUsage;
1162                     }
1163                     else
1164                     {
1165                         edmType = GetPrimitiveType(scalarType, providerManifest);
1166                     }
1167                 }
1168                 else
1169                 {
1170                     edmType = (EdmType)LoadSchemaElement(type,
1171                         providerManifest,
1172                         convertedItemCache,
1173                         newGlobalItems);
1174
1175                     // Neither FunctionImport nor its Parameters can have facets when defined in CSDL so for enums, 
1176                     // since they are only a CSpace concept, we need to process facets only on model functions 
1177                     if (isModelFunction && type is Som.SchemaEnumType)
1178                     {
1179                         Debug.Assert(somFunction.Schema.DataModel == Som.SchemaDataModelOption.EntityDataModel, "Enums live only in CSpace");
1180
1181                         if (somParameter != null)
1182                         {
1183                             somParameter.ValidateAndSetTypeUsage(edmType);
1184                             return somParameter.TypeUsage;
1185                         }
1186                         else if (somFunction != null)
1187                         {
1188                             var modelFunction = ((Som.ModelFunction)somFunction);
1189                             modelFunction.ValidateAndSetTypeUsage(edmType);
1190                             return modelFunction.TypeUsage;
1191                         }
1192                         else
1193                         {
1194                             Debug.Fail("Should never get here.");
1195                         }
1196                     }
1197                 }
1198             }
1199             else if (type is Som.TypeElement)
1200             {
1201                 Som.TypeElement typeElement = type as Som.TypeElement;
1202                 edmType = typeElement.PrimitiveType;
1203             }
1204             else
1205             {
1206                 Som.ScalarType typeElement = type as Som.ScalarType;
1207                 edmType = typeElement.Type;
1208             }
1209
1210             //Construct type usage
1211             TypeUsage usage;
1212             if (collectionKind != CollectionKind.None)
1213             {
1214                 usage = convertedItemCache.GetCollectionTypeUsageWithNullFacets(edmType);
1215             }
1216             else
1217             {
1218                 if (edmType is EntityType && isRefType)
1219                 {
1220                     usage = TypeUsage.Create(new RefType(edmType as EntityType));
1221                 }
1222                 else
1223                 {
1224                     usage = convertedItemCache.GetTypeUsageWithNullFacets(edmType);
1225                 }
1226             }
1227
1228             return usage;
1229
1230         }
1231
1232         /// <summary>
1233         /// Converts the ParameterDirection into a ParameterMode
1234         /// </summary>
1235         /// <param name="parameterDirection">The ParameterDirection to convert</param>
1236         /// <returns>ParameterMode</returns>
1237         private static ParameterMode GetParameterMode(ParameterDirection parameterDirection)
1238         {
1239             Debug.Assert(
1240                 parameterDirection == ParameterDirection.Input
1241                 || parameterDirection == ParameterDirection.InputOutput
1242                 || parameterDirection == ParameterDirection.Output,
1243                 "Inconsistent metadata error");
1244
1245             switch (parameterDirection)
1246             {
1247                 case ParameterDirection.Input:
1248                     return ParameterMode.In;
1249
1250                 case ParameterDirection.Output:
1251                     return ParameterMode.Out;
1252
1253                 case ParameterDirection.InputOutput:
1254                 default:
1255                     return ParameterMode.InOut;
1256             }
1257         }
1258
1259         /// <summary>
1260         /// Apply the facet values 
1261         /// </summary>
1262         /// <param name="sourceType">The source TypeUsage</param>
1263         /// <param name="targetType">The primitive or enum type of the target</param>
1264         private static void ApplyTypePropertyFacets(TypeUsage sourceType, ref TypeUsage targetType)
1265         {
1266             Dictionary<string, Facet> newFacets = targetType.Facets.ToDictionary(f => f.Name);
1267             bool madeChange = false;
1268             foreach (Facet sourceFacet in sourceType.Facets)
1269             {
1270                 Facet targetFacet;
1271                 if (newFacets.TryGetValue(sourceFacet.Name, out targetFacet))
1272                 {
1273                     if (!targetFacet.Description.IsConstant)
1274                     {
1275                         madeChange = true;
1276                         newFacets[targetFacet.Name] = Facet.Create(targetFacet.Description, sourceFacet.Value);
1277                     }
1278                 }
1279                 else
1280                 {
1281                     madeChange = true;
1282                     newFacets.Add(sourceFacet.Name, sourceFacet);
1283                 }
1284             }
1285
1286             if (madeChange)
1287             {
1288                 targetType = TypeUsage.Create(targetType.EdmType, newFacets.Values);
1289             }
1290         }
1291
1292         /// <summary>
1293         /// Populate the facets on the TypeUsage object for a property
1294         /// </summary>
1295         /// <param name="somProperty">The property containing the information</param>
1296         /// <param name="propertyTypeUsage">The type usage object where to populate facet</param>
1297         /// <param name="providerManifest">The provider manifest to be used for conversion</param>
1298         private static void PopulateGeneralFacets(Som.StructuredProperty somProperty,
1299                                                   DbProviderManifest providerManifest,
1300                                                   ref TypeUsage propertyTypeUsage)
1301         {
1302             bool madeChanges = false;
1303             Dictionary<string, Facet> facets = propertyTypeUsage.Facets.ToDictionary(f => f.Name);
1304             if (!somProperty.Nullable)
1305             {
1306                 facets[DbProviderManifest.NullableFacetName] = Facet.Create(MetadataItem.NullableFacetDescription, false);
1307                 madeChanges = true;
1308             }
1309
1310             if (somProperty.Default != null)
1311             {
1312                 facets[DbProviderManifest.DefaultValueFacetName] = Facet.Create(MetadataItem.DefaultValueFacetDescription, somProperty.DefaultAsObject);
1313                 madeChanges = true;
1314             }
1315
1316             //This is not really a general facet
1317             //If we are dealing with a 1.1 Schema, Add a facet for CollectionKind
1318             if (somProperty.Schema.SchemaVersion == XmlConstants.EdmVersionForV1_1)
1319             {
1320                 Facet newFacet = Facet.Create(MetadataItem.CollectionKindFacetDescription, somProperty.CollectionKind);
1321                 facets.Add(newFacet.Name, newFacet);
1322                 madeChanges = true;
1323             }
1324
1325             if (madeChanges)
1326             {
1327                 propertyTypeUsage = TypeUsage.Create(propertyTypeUsage.EdmType, facets.Values);
1328             }
1329         }
1330
1331         private static DataSpace GetDataSpace(DbProviderManifest providerManifest)
1332         {
1333             Debug.Assert(providerManifest != null, "null provider manifest will be consider as SSpace");
1334             // Target attributes is for types and sets in target space.
1335             if (providerManifest is EdmProviderManifest)
1336             {
1337                 return DataSpace.CSpace;
1338             }
1339             else
1340             {
1341                 return DataSpace.SSpace;
1342             }
1343         }
1344
1345         /// <summary>
1346         /// Get a primitive type when converting a CSDL schema
1347         /// </summary>
1348         /// <param name="scalarType">The schema type representing the primitive type</param>
1349         /// <param name="providerManifest">The provider manifest for retrieving the store types</param>
1350         private static PrimitiveType GetPrimitiveType(Som.ScalarType scalarType,
1351                                                           DbProviderManifest providerManifest)
1352         {
1353             PrimitiveType returnValue = null;
1354             string scalarTypeName = scalarType.Name;
1355
1356             foreach (PrimitiveType primitiveType in providerManifest.GetStoreTypes())
1357             {
1358                 if (primitiveType.Name == scalarTypeName)
1359                 {
1360                     returnValue = primitiveType;
1361                     break;
1362                 }
1363             }
1364
1365             Debug.Assert(scalarType != null, "Som scalar type should always resolve to a primitive type");
1366             return returnValue;
1367         }
1368
1369         // This will update the sentinel values in the facets if required
1370         private static void UpdateSentinelValuesInFacets(ref TypeUsage typeUsage)
1371         {
1372             // For string and decimal types, replace the sentinel by the max possible value
1373             PrimitiveType primitiveType = (PrimitiveType)typeUsage.EdmType;
1374             if (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.String ||
1375                 primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Binary)
1376             {
1377                 Facet maxLengthFacet = typeUsage.Facets[EdmProviderManifest.MaxLengthFacetName];
1378                 if (Helper.IsUnboundedFacetValue(maxLengthFacet))
1379                 {
1380                     typeUsage = typeUsage.ShallowCopy(
1381                             new FacetValues
1382                             {
1383                                 MaxLength = Helper.GetFacet(primitiveType.FacetDescriptions,
1384                                                    EdmProviderManifest.MaxLengthFacetName).MaxValue
1385                             });
1386                 }
1387             }
1388
1389         }
1390         #endregion
1391
1392         #region Nested types
1393         /// <summary>
1394         /// Cache containing item collection and type usages to support looking up and generating
1395         /// metadata types.
1396         /// </summary>
1397         internal class ConversionCache
1398         {
1399             #region Fields
1400             internal readonly ItemCollection ItemCollection;
1401             private readonly Dictionary<EdmType, TypeUsage> _nullFacetsTypeUsage;
1402             private readonly Dictionary<EdmType, TypeUsage> _nullFacetsCollectionTypeUsage;
1403             #endregion
1404
1405             #region Constructors
1406             internal ConversionCache(ItemCollection itemCollection)
1407             {
1408                 this.ItemCollection = itemCollection;
1409                 this._nullFacetsTypeUsage = new Dictionary<EdmType, TypeUsage>();
1410                 this._nullFacetsCollectionTypeUsage = new Dictionary<EdmType, TypeUsage>();
1411             }
1412             #endregion
1413
1414             #region Methods
1415             /// <summary>
1416             /// Gets type usage for the given type with null facet values. Caches usage to avoid creating
1417             /// redundant type usages.
1418             /// </summary>
1419             internal TypeUsage GetTypeUsageWithNullFacets(EdmType edmType)
1420             {
1421                 // check for cached result
1422                 TypeUsage result;
1423                 if (_nullFacetsTypeUsage.TryGetValue(edmType, out result))
1424                 {
1425                     return result;
1426                 }
1427
1428                 // construct result
1429                 result = TypeUsage.Create(edmType, FacetValues.NullFacetValues);
1430
1431                 // cache result
1432                 _nullFacetsTypeUsage.Add(edmType, result);
1433
1434                 return result;
1435             }
1436
1437             /// <summary>
1438             /// Gets collection type usage for the given type with null facet values. Caches usage to avoid creating
1439             /// redundant type usages.
1440             /// </summary>
1441             internal TypeUsage GetCollectionTypeUsageWithNullFacets(EdmType edmType)
1442             {
1443                 // check for cached result
1444                 TypeUsage result;
1445                 if (_nullFacetsCollectionTypeUsage.TryGetValue(edmType, out result))
1446                 {
1447                     return result;
1448                 }
1449
1450                 // construct collection type from cached element type
1451                 TypeUsage elementTypeUsage = GetTypeUsageWithNullFacets(edmType);
1452                 result = TypeUsage.Create(new CollectionType(elementTypeUsage), FacetValues.NullFacetValues);
1453
1454                 // cache result
1455                 _nullFacetsCollectionTypeUsage.Add(edmType, result);
1456
1457                 return result;
1458             }
1459             #endregion
1460         }
1461         #endregion
1462     }
1463 }