Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntity / System / Data / Metadata / Converter.cs / 1 / Converter.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....],[....] //--------------------------------------------------------------------- using Som = System.Data.EntityModel.SchemaObjectModel; using System.Data.Common; using System.Diagnostics; using System.Data.Objects.DataClasses; using System.Collections.Generic; using System.Globalization; using System.Text; using System.Linq; namespace System.Data.Metadata.Edm { ////// Helper Class for converting SOM objects to metadata objects /// This class should go away once we have completely integrated SOM and metadata /// internal static class Converter { #region Constructor ////// Static constructor for creating FacetDescription objects that we use /// static Converter() { // Create the enum types that we will need EnumType concurrencyModeType = new EnumType(EdmProviderManifest.ConcurrencyModeFacetName, EdmConstants.EdmNamespace, DataSpace.CSpace); foreach (string name in Enum.GetNames(typeof(ConcurrencyMode))) { concurrencyModeType.AddMember(new EnumMember(name)); } EnumType storeGeneratedPatternType = new EnumType(EdmProviderManifest.StoreGeneratedPatternFacetName, EdmConstants.EdmNamespace, DataSpace.CSpace); foreach (string name in Enum.GetNames(typeof(StoreGeneratedPattern))) { storeGeneratedPatternType.AddMember(new EnumMember(name)); } // Now create the facet description objects ConcurrencyModeFacet = new FacetDescription(EdmProviderManifest.ConcurrencyModeFacetName, concurrencyModeType, null, null, ConcurrencyMode.None); StoreGeneratedPatternFacet = new FacetDescription(EdmProviderManifest.StoreGeneratedPatternFacetName, storeGeneratedPatternType, null, null, StoreGeneratedPattern.None); CollationFacet = new FacetDescription(EdmProviderManifest.CollationFacetName, MetadataItem.EdmProviderManifest.GetPrimitiveType(PrimitiveTypeKind.String), null, null, string.Empty); } #endregion #region Fields internal static readonly FacetDescription ConcurrencyModeFacet; internal static readonly FacetDescription StoreGeneratedPatternFacet; internal static readonly FacetDescription CollationFacet; #endregion #region Methods ////// Converts a schema from SOM into Metadata /// /// The SOM schema to convert /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects internal static IEnumerableConvertSchema(Som.Schema somSchema, DbProviderManifest providerManifest, ItemCollection itemCollection) { Dictionary newGlobalItems = new Dictionary (); ConvertSchema(somSchema, providerManifest, new ConversionCache(itemCollection), newGlobalItems); return newGlobalItems.Values; } internal static IEnumerable ConvertSchema(IList somSchemas, DbProviderManifest providerManifest, ItemCollection itemCollection) { Dictionary newGlobalItems = new Dictionary (); ConversionCache conversionCache = new ConversionCache(itemCollection); foreach (Som.Schema somSchema in somSchemas) { ConvertSchema(somSchema, providerManifest, conversionCache, newGlobalItems); } return newGlobalItems.Values; } private static void ConvertSchema(Som.Schema somSchema, DbProviderManifest providerManifest, ConversionCache convertedItemCache, Dictionary newGlobalItems) { foreach (Som.SchemaType element in somSchema.SchemaTypes) { LoadSchemaElement(element, providerManifest, convertedItemCache, newGlobalItems); } foreach (Som.SchemaEntityType element in somSchema.SchemaTypes.OfType ()) { LoadEntityTypePhase2(element, providerManifest, convertedItemCache, newGlobalItems); } if (convertedItemCache.ItemCollection.DataSpace == DataSpace.CSpace) { EdmItemCollection edmCollection = (EdmItemCollection)convertedItemCache.ItemCollection; //Get the version of the SomSchema and update the EdmVersion to be the Maximum of all the //versions of the schemas that are being loaded in this item collection. edmCollection.EdmVersion = Math.Max(somSchema.EdmVersion, edmCollection.EdmVersion); } } /// /// Loads a schema element /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The item resulting from the load private static MetadataItem LoadSchemaElement(Som.SchemaType element, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { // Try to fetch from the collection first GlobalItem item; Debug.Assert(!convertedItemCache.ItemCollection.TryGetValue(element.FQName, false, out item), "Som should have checked for duplicate items"); // Try to fetch in our collection of new GlobalItems if (newGlobalItems.TryGetValue(element, out item)) { return item; } Som.EntityContainer entityContainer = element as Som.EntityContainer; // Perform different conversion depending on the type of the SOM object if (entityContainer!=null) { item = ConvertToEntityContainer(entityContainer, providerManifest, convertedItemCache, newGlobalItems); } else if (element is Som.SchemaEntityType) { item = ConvertToEntityType((Som.SchemaEntityType)element, providerManifest, convertedItemCache, newGlobalItems); } else if (element is Som.Relationship) { item = ConvertToAssociationType((Som.Relationship)element, providerManifest, convertedItemCache, newGlobalItems); } else if (element is Som.SchemaComplexType) { item = ConvertToComplexType((Som.SchemaComplexType)element, providerManifest, convertedItemCache, newGlobalItems); } else if (element is Som.Function) { item = ConvertToFunction((Som.Function)element, providerManifest, convertedItemCache, null, newGlobalItems); } else { // the only type we don't handle is the ProviderManifest TypeElement // if it is anything else, it is probably a mistake Debug.Assert(element is Som.TypeElement && element.Schema.DataModel == Som.SchemaDataModelOption.ProviderManifestModel, "Unknown Type in somschema"); return null; } return item; } /// /// Converts an entity container from SOM to metadata /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The entity container object resulting from the convert private static EntityContainer ConvertToEntityContainer(Som.EntityContainer element, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { // Creating a new entity container object and populate with converted entity set objects EntityContainer entityContainer = new EntityContainer(element.Name, GetDataSpace(providerManifest)); newGlobalItems.Add(element, entityContainer); foreach (Som.EntityContainerEntitySet entitySet in element.EntitySets) { entityContainer.AddEntitySetBase(ConvertToEntitySet(entitySet, entityContainer.Name, providerManifest, convertedItemCache, newGlobalItems)); } // Populate with converted relationship set objects foreach (Som.EntityContainerRelationshipSet relationshipSet in element.RelationshipSets) { Debug.Assert(relationshipSet.Relationship.RelationshipKind == RelationshipKind.Association, "We do not support containment set"); entityContainer.AddEntitySetBase(ConvertToAssociationSet(relationshipSet, providerManifest, convertedItemCache, entityContainer, newGlobalItems)); } // Populate with converted function imports foreach (Som.Function functionImport in element.FunctionImports) { entityContainer.AddFunctionImport(ConvertToFunction(functionImport, providerManifest, convertedItemCache, entityContainer, newGlobalItems)); } // Extract the optional Documentation if (element.Documentation != null) { entityContainer.Documentation = ConvertToDocumentation(element.Documentation); } AddOtherContent(element, entityContainer); return entityContainer; } /// /// Converts an entity type from SOM to metadata /// /// This method should only build the internally contained and vertical part of the EntityType (keys, properties, and base types) but not /// sideways parts (NavigationProperties) that go between types or we risk trying to access and EntityTypes keys, from the referenctial constraint, /// before the base type, which has the keys, is setup yet. /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The entity type object resulting from the convert private static EntityType ConvertToEntityType(Som.SchemaEntityType element, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { string[] keyMembers = null; // Check if this type has keys if (element.DeclaredKeyProperties.Count != 0) { keyMembers = new string[element.DeclaredKeyProperties.Count]; for (int i = 0; i < keyMembers.Length; i++) { //Add the name of the key property to the list of //key properties keyMembers[i] = (element.DeclaredKeyProperties[i].Property.Name); } } EdmProperty[] properties = new EdmProperty[element.Properties.Count]; int index = 0; foreach (Som.StructuredProperty somProperty in element.Properties) { properties[index++] = ConvertToProperty(somProperty, providerManifest, convertedItemCache, newGlobalItems); } EntityType entityType = new EntityType(element.Name, element.Namespace, GetDataSpace(providerManifest), keyMembers, properties); if (element.BaseType != null) { entityType.BaseType = (EdmType)(LoadSchemaElement(element.BaseType, providerManifest, convertedItemCache, newGlobalItems)); } // set the abstract and sealed type values for the entity type entityType.Abstract = element.IsAbstract; // Extract the optional Documentation if (element.Documentation != null) { entityType.Documentation = ConvertToDocumentation(element.Documentation); } AddOtherContent(element, entityType); newGlobalItems.Add(element, entityType); return entityType; } private static void LoadEntityTypePhase2(Som.SchemaEntityType element, DbProviderManifest providerManifest, ConversionCache convertedItemCache, Dictionary newGlobalItems) { EntityType entityType = (EntityType)newGlobalItems[element]; // Since Navigation properties are internal and not part of member collection, we // need to initialize the base class first before we start adding the navigation property // this will ensure that all the base navigation properties are initialized foreach (Som.NavigationProperty somNavigationProperty in element.NavigationProperties) { entityType.AddMember(ConvertToNavigationProperty(entityType, somNavigationProperty, providerManifest, convertedItemCache, newGlobalItems)); } } /// /// Converts an complex type from SOM to metadata /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The complex type object resulting from the convert private static ComplexType ConvertToComplexType(Som.SchemaComplexType element, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { ComplexType complexType = new ComplexType(element.Name, element.Namespace, GetDataSpace(providerManifest)); newGlobalItems.Add(element, complexType); foreach (Som.StructuredProperty somProperty in element.Properties) { complexType.AddMember(ConvertToProperty(somProperty, providerManifest, convertedItemCache, newGlobalItems)); } // set the abstract and sealed type values for the entity type complexType.Abstract = element.IsAbstract; if (element.BaseType != null) { complexType.BaseType = (EdmType)(LoadSchemaElement(element.BaseType, providerManifest, convertedItemCache, newGlobalItems)); } // Extract the optional Documentation if (element.Documentation != null) { complexType.Documentation = ConvertToDocumentation(element.Documentation); } AddOtherContent(element, complexType); return complexType; } /// /// Converts an association type from SOM to metadata /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The association type object resulting from the convert private static AssociationType ConvertToAssociationType(Som.Relationship element, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { Debug.Assert(element.RelationshipKind == RelationshipKind.Association); AssociationType associationType = new AssociationType(element.Name, element.Namespace, GetDataSpace(providerManifest)); newGlobalItems.Add(element, associationType); foreach (Som.RelationshipEnd end in element.Ends) { Som.SchemaType entityTypeElement = end.Type; EntityType endEntityType = (EntityType)LoadSchemaElement(entityTypeElement, providerManifest, convertedItemCache, newGlobalItems); AssociationEndMember endMember = InitializeAssociationEndMember(associationType, end, endEntityType); AddOtherContent(end, endMember); // Loop through and convert the operations foreach (Som.OnOperation operation in end.Operations) { // Process only the ones that we recognize if (operation.Operation != Som.Operation.Delete) { continue; } // Determine the action for this operation OperationAction action = OperationAction.None; switch (operation.Action) { case Som.Action.Cascade: action = OperationAction.Cascade; break; case Som.Action.None: action = OperationAction.None; break; default: throw EntityUtil.OperationActionNotSupported(); } endMember.DeleteBehavior = action; } // Extract optional Documentation hanging off the end element if (end.Documentation != null) { endMember.Documentation = ConvertToDocumentation(end.Documentation); } } Debug.Assert(associationType.ReferentialConstraints.Count == 0, "This must never have been initialized"); for (int i = 0; i < element.Constraints.Count; i++) { Som.ReferentialConstraint constraint = element.Constraints[i]; AssociationEndMember fromMember = (AssociationEndMember) associationType.Members[constraint.PrincipalRole.Name]; AssociationEndMember toMember = (AssociationEndMember)associationType.Members[constraint.DependentRole.Name]; EntityTypeBase fromEntityType = ((RefType)fromMember.TypeUsage.EdmType).ElementType; EntityTypeBase toEntityType = ((RefType)toMember.TypeUsage.EdmType).ElementType; ReferentialConstraint referentialConstraint = new ReferentialConstraint(fromMember, toMember, GetProperties(fromEntityType, constraint.PrincipalRole.RoleProperties), GetProperties(toEntityType, constraint.DependentRole.RoleProperties)); // Attach the optional Documentation if (constraint.Documentation != null) referentialConstraint.Documentation = ConvertToDocumentation(constraint.Documentation); if (fromMember.Documentation != null) referentialConstraint.FromRole.Documentation = ConvertToDocumentation(constraint.PrincipalRole.Documentation); if (toMember.Documentation != null) referentialConstraint.ToRole.Documentation = ConvertToDocumentation(constraint.DependentRole.Documentation); associationType.AddReferentialConstraint(referentialConstraint); AddOtherContent(element.Constraints[i], referentialConstraint); } // Extract the optional Documentation if (element.Documentation != null) { associationType.Documentation = ConvertToDocumentation(element.Documentation); } AddOtherContent(element, associationType); return associationType; } /// /// Initialize the end member if its not initialized already /// /// /// /// private static AssociationEndMember InitializeAssociationEndMember(AssociationType associationType, Som.IRelationshipEnd end, EntityType endMemberType) { AssociationEndMember associationEnd; EdmMember member; // make sure that the end is not initialized as of yet if (!associationType.Members.TryGetValue(end.Name, false/*ignoreCase*/, out member)) { // Create the end member and add the operations associationEnd = new AssociationEndMember(end.Name, endMemberType.GetReferenceType(), end.Multiplicity); associationType.AddKeyMember(associationEnd); } else { associationEnd = (AssociationEndMember)member; } //Extract the optional Documentation Som.RelationshipEnd relationshipEnd = end as Som.RelationshipEnd; if (relationshipEnd != null && (relationshipEnd.Documentation != null)) { associationEnd.Documentation = ConvertToDocumentation(relationshipEnd.Documentation); } return associationEnd; } private static EdmProperty[] GetProperties(EntityTypeBase entityType, IListproperties) { Debug.Assert(properties.Count != 0); EdmProperty[] result = new EdmProperty[properties.Count]; for (int i = 0; i < properties.Count; i++) { result[i] = (EdmProperty) entityType.Members[properties[i].Name]; } return result; } private static void AddOtherContent(Som.SchemaElement element, MetadataItem item) { if (element.OtherContent.Count > 0) { item.AddMetadataProperties(element.OtherContent); } } /// /// Converts an entity set from SOM to metadata /// /// The SOM element to process /// the name of the container this will be added to /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The entity set object resulting from the convert private static EntitySet ConvertToEntitySet(Som.EntityContainerEntitySet set, string containerName, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { EntitySet entitySet = new EntitySet(set.Name,set.DbSchema,set.Table, set.DefiningQuery, (EntityType)LoadSchemaElement(set.EntityType, providerManifest, convertedItemCache, newGlobalItems)); // Extract the optional Documentation if (set.Documentation != null) { entitySet.Documentation = ConvertToDocumentation(set.Documentation); } AddOtherContent(set, entitySet); return entitySet; } /// /// Converts an entity set from SOM to metadata /// /// The SOM element to process /// ///The entity set object resulting from the convert private static EntitySet GetEntitySet(Som.EntityContainerEntitySet set, EntityContainer container) { return container.GetEntitySetByName(set.Name, false); } ////// Converts an association set from SOM to metadata /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion /// ///The association set object resulting from the convert private static AssociationSet ConvertToAssociationSet(Som.EntityContainerRelationshipSet relationshipSet, DbProviderManifest providerManifest, ConversionCache convertedItemCache, EntityContainer container, DictionarynewGlobalItems) { Debug.Assert(relationshipSet.Relationship.RelationshipKind == RelationshipKind.Association); AssociationType associationType = (AssociationType)LoadSchemaElement((Som.SchemaType)relationshipSet.Relationship, providerManifest, convertedItemCache, newGlobalItems); AssociationSet associationSet = new AssociationSet(relationshipSet.Name, associationType); foreach (Som.EntityContainerRelationshipSetEnd end in relationshipSet.Ends) { //-- need the EntityType for the end EntityType endEntityType = (EntityType)LoadSchemaElement(end.EntitySet.EntityType, providerManifest, convertedItemCache, newGlobalItems); //-- need to get the end member AssociationEndMember endMember = (AssociationEndMember) associationType.Members[end.Name]; //-- create the end AssociationSetEnd associationSetEnd = new AssociationSetEnd(GetEntitySet(end.EntitySet, container), associationSet, endMember); AddOtherContent(end, associationSetEnd); associationSet.AddAssociationSetEnd(associationSetEnd); // Extract optional Documentation hanging off the end element if (end.Documentation != null) { associationSetEnd.Documentation = ConvertToDocumentation(end.Documentation); } } // Extract the optional Documentation if (relationshipSet.Documentation != null) { associationSet.Documentation = ConvertToDocumentation(relationshipSet.Documentation); } AddOtherContent(relationshipSet, associationSet); return associationSet; } /// /// Converts a property from SOM to metadata /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The property object resulting from the convert private static EdmProperty ConvertToProperty(Som.StructuredProperty somProperty, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { EdmProperty property; // Get the appropriate type object for this type, for primitive types, get the facet values for the primitive type // property as a type usage object as well TypeUsage typeUsage = null; Som.ScalarType scalarType = somProperty.Type as Som.ScalarType; if (scalarType != null) { if (somProperty.Schema.DataModel == Som.SchemaDataModelOption.EntityDataModel) { // csdl typeUsage = GetCsdlPrimitiveTypeUsageWithFacets(somProperty, convertedItemCache); } else { // parsing ssdl typeUsage = somProperty.TypeUsage; UpdateSentinelValuesInFacets(ref typeUsage); } } else { EdmType propertyType = (EdmType)LoadSchemaElement(somProperty.Type, providerManifest, convertedItemCache, newGlobalItems); if (somProperty.CollectionKind != CollectionKind.None) { propertyType = new CollectionType(propertyType); } typeUsage = TypeUsage.Create(propertyType); } PopulateGeneralFacets(somProperty, providerManifest, ref typeUsage); property = new EdmProperty(somProperty.Name, typeUsage); // Extract the optional Documentation if (somProperty.Documentation != null) { property.Documentation = ConvertToDocumentation(somProperty.Documentation); } AddOtherContent(somProperty, property); return property; } /// /// Converts a navigation property from SOM to metadata /// /// entity type on which this navigation property was declared /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The property object resulting from the convert private static NavigationProperty ConvertToNavigationProperty(EntityType declaringEntityType, Som.NavigationProperty somNavigationProperty, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { // Navigation properties cannot be primitive types, so we can ignore the possibility of having primitive type // facets EntityType toEndEntityType = (EntityType)LoadSchemaElement(somNavigationProperty.Type, providerManifest, convertedItemCache, newGlobalItems); EdmType edmType = toEndEntityType; // Also load the relationship Type that this navigation property represents AssociationType relationshipType = (AssociationType)LoadSchemaElement((Som.Relationship)somNavigationProperty.Relationship, providerManifest, convertedItemCache, newGlobalItems); Som.IRelationshipEnd somRelationshipEnd = null; somNavigationProperty.Relationship.TryGetEnd(somNavigationProperty.ToEnd.Name, out somRelationshipEnd); if (somRelationshipEnd.Multiplicity == RelationshipMultiplicity.Many) { edmType = toEndEntityType.GetCollectionType(); } else { Debug.Assert(somRelationshipEnd.Multiplicity != RelationshipMultiplicity.Many); edmType = toEndEntityType; } TypeUsage typeUsage; if (somRelationshipEnd.Multiplicity == RelationshipMultiplicity.One) { typeUsage = TypeUsage.Create(edmType, new FacetValues{Nullable = false}); } else { typeUsage = TypeUsage.Create(edmType); } // We need to make sure that both the ends of the relationtype are initialized. If there are not, then we should // initialize them here InitializeAssociationEndMember(relationshipType, somNavigationProperty.ToEnd, toEndEntityType); InitializeAssociationEndMember(relationshipType, somNavigationProperty.FromEnd, declaringEntityType); // The type of the navigation property must be a ref or collection depending on which end they belong to NavigationProperty navigationProperty = new NavigationProperty(somNavigationProperty.Name, typeUsage); navigationProperty.RelationshipType = relationshipType; navigationProperty.ToEndMember = (RelationshipEndMember)relationshipType.Members[somNavigationProperty.ToEnd.Name]; navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[somNavigationProperty.FromEnd.Name]; // Extract the optional Documentation if (somNavigationProperty.Documentation != null) { navigationProperty.Documentation = ConvertToDocumentation(somNavigationProperty.Documentation); } AddOtherContent(somNavigationProperty, navigationProperty); return navigationProperty; } /// /// Converts a function from SOM to metadata /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// For function imports, the entity container including the function declaration /// The new GlobalItem objects that are created as a result of this conversion ///The function object resulting from the convert private static EdmFunction ConvertToFunction(Som.Function somFunction, DbProviderManifest providerManifest, ConversionCache convertedItemCache, EntityContainer entityContainer, DictionarynewGlobalItems) { // If we already have it, don't bother converting GlobalItem globalItem = null; // if we are converted the function import, we need not check the global items collection, // since the function imports are local to the entity container if (!somFunction.IsFunctionImport && newGlobalItems.TryGetValue(somFunction, out globalItem)) { return (EdmFunction)globalItem; } FunctionParameter returnParameter = null; bool areConvertingForProviderManifest = somFunction.Schema.DataModel == Som.SchemaDataModelOption.ProviderManifestModel; TypeUsage returnType = GetFunctionTypeUsage(somFunction.ReturnType, providerManifest, areConvertingForProviderManifest, somFunction.Type, somFunction.CollectionKind, somFunction, convertedItemCache, newGlobalItems); if (null != returnType) { // Create the return parameter object, need to set the declaring type explicitly on the return parameter // because we aren't adding it to the members collection returnParameter = new FunctionParameter(EdmConstants.ReturnType, returnType, ParameterMode.ReturnValue); } EntitySet entitySet = null; if (null != somFunction.EntitySet) { Debug.Assert(null != entityContainer, "only function imports may declare a entity set " + "and function imports are always scoped to an entity container"); entitySet = GetEntitySet(somFunction.EntitySet, entityContainer); } List parameters = new List (); foreach (Som.Parameter somParameter in somFunction.Parameters) { TypeUsage parameterType = GetFunctionTypeUsage(somParameter, providerManifest, areConvertingForProviderManifest, somParameter.Type, somParameter.CollectionKind, somParameter, convertedItemCache, newGlobalItems); FunctionParameter parameter = new FunctionParameter(somParameter.Name, parameterType, GetParameterMode(somParameter.ParameterDirection)); AddOtherContent(somParameter, parameter); if (somParameter.Documentation != null) { parameter.Documentation = ConvertToDocumentation(somParameter.Documentation); } parameters.Add(parameter); } EdmFunction function = new EdmFunction(somFunction.Name, somFunction.Schema.Namespace, GetDataSpace(providerManifest), new EdmFunctionPayload { Schema = somFunction.DbSchema, StoreFunctionName = somFunction.StoreFunctionName, CommandText = somFunction.CommandText, EntitySet = entitySet, IsAggregate = somFunction.IsAggregate, IsBuiltIn = somFunction.IsBuiltIn, IsNiladic = somFunction.IsNiladicFunction, IsComposable = somFunction.IsComposable, IsFromProviderManifest = areConvertingForProviderManifest, ReturnParameter = returnParameter, Parameters = parameters.ToArray(), ParameterTypeSemantics = somFunction.ParameterTypeSemantics, }); // Add this function to new global items, only if it is not a function import if (!somFunction.IsFunctionImport) { newGlobalItems.Add(somFunction, function); } //Check if we already converted functions since we are loading it from //ssdl we could see functions many times. GlobalItem returnFunction = null; Debug.Assert(!convertedItemCache.ItemCollection.TryGetValue(function.Identity, false, out returnFunction), "Function duplicates must be checked by som"); // Extract the optional Documentation if (somFunction.Documentation != null) { function.Documentation = ConvertToDocumentation(somFunction.Documentation); } AddOtherContent(somFunction, function); return function; } /// /// Converts an SOM Documentation node to a metadata Documentation construct /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The Do----mentation object resulting from the convert operation private static Documentation ConvertToDocumentation(Som.DocumentationElement element) { Debug.Assert(null != element, "ConvertToDocumentation cannot be invoked with a null Som.Documentation element"); return element.MetadataDocumentation; } private static TypeUsage GetFunctionTypeUsage(Som.FacetEnabledSchemaElement somParameter, DbProviderManifest providerManifest, bool areConvertingForProviderManifest, Som.SchemaType type, CollectionKind collectionKind, Som.SchemaElement schemaElement, ConversionCache convertedItemCache, DictionarynewGlobalItems) { if (null != somParameter && somParameter.HasUserDefinedFacets) { return somParameter.TypeUsage; } if (null == type) { return null; } EdmType edmType; if (!areConvertingForProviderManifest) { // SOM verifies the type is either scalar, row, or entity Som.ScalarType scalarType = type as Som.ScalarType; if (null != scalarType) { edmType = GetSsdlPrimitiveType(scalarType, providerManifest); } else { edmType = (EdmType)LoadSchemaElement(type, providerManifest, convertedItemCache, newGlobalItems); } } else if (type is Som.TypeElement) { Som.TypeElement typeElement = type as Som.TypeElement; edmType = typeElement.PrimitiveType; } else { Som.ScalarType typeElement = type as Som.ScalarType; edmType = typeElement.Type; } TypeUsage usage; if (collectionKind != CollectionKind.None) { usage = convertedItemCache.GetCollectionTypeUsageWithNullFacets(edmType); } else { usage = convertedItemCache.GetTypeUsageWithNullFacets(edmType); } return usage; } /// /// Converts the ParameterDirection into a ParameterMode /// /// The ParameterDirection to convert ///ParameterMode private static ParameterMode GetParameterMode(ParameterDirection parameterDirection) { switch (parameterDirection) { case ParameterDirection.Input: return ParameterMode.In; case ParameterDirection.Output: return ParameterMode.Out; case ParameterDirection.InputOutput: return ParameterMode.InOut; default: throw EntityUtil.MetadataGeneralError(); } } ////// Apply the facet values from the property which are specific to primitive types to the given list of facets /// /// The source TypeUsage /// The PrimativeType of the target private static void ApplyPrimitiveTypePropertyFacets(TypeUsage sourceType, ref TypeUsage targetType) { DictionarynewFacets = targetType.Facets.ToDictionary(f => f.Name); bool madeChange = false; foreach (Facet sourceFacet in sourceType.Facets) { Facet targetFacet; if(newFacets.TryGetValue(sourceFacet.Name, out targetFacet)) { if (!targetFacet.Description.IsConstant) { madeChange = true; newFacets[targetFacet.Name] = Facet.Create(targetFacet.Description, sourceFacet.Value); } } else { madeChange = true; newFacets.Add(sourceFacet.Name, sourceFacet); } } if (madeChange) { targetType = TypeUsage.Create(targetType.EdmType, newFacets.Values); } } /// /// Populate the facets on the TypeUsage object fora property /// /// The property containing the information /// The type usage object where to populate facet /// The provider manifest to be used for conversion private static void PopulateGeneralFacets(Som.StructuredProperty somProperty, DbProviderManifest providerManifest, ref TypeUsage propertyTypeUsage) { bool madeChanges = false; Dictionaryfacets = propertyTypeUsage.Facets.ToDictionary(f => f.Name); if (!somProperty.Nullable) { facets[DbProviderManifest.NullableFacetName] = Facet.Create(MetadataItem.NullableFacetDescription, false); madeChanges = true; } if (somProperty.Default != null) { facets[DbProviderManifest.DefaultValueFacetName] = Facet.Create(MetadataItem.DefaultValueFacetDescription, somProperty.DefaultAsObject); madeChanges = true; } //This is not really a general facet //If we are dealing with a 1.1 Schema, Add a facet for CollectionKind if (somProperty.Schema.EdmVersion == XmlConstants.EdmVersionForV1_1) { Facet newFacet = Facet.Create(MetadataItem.CollectionKindFacetDescription, somProperty.CollectionKind); facets.Add(newFacet.Name, newFacet); madeChanges = true; } if (madeChanges) { propertyTypeUsage = TypeUsage.Create(propertyTypeUsage.EdmType, facets.Values); } } private static DataSpace GetDataSpace(DbProviderManifest providerManifest) { // Target attributes is for types and sets in target space. if (providerManifest is EdmProviderManifest) { return DataSpace.CSpace; } else { return DataSpace.SSpace; } } /// /// Get a primitive type when converting a CSDL schema /// /// The schema type representing the primitive type /// The provider manifest for retrieving the store types private static PrimitiveType GetSsdlPrimitiveType(Som.ScalarType scalarType, DbProviderManifest providerManifest) { PrimitiveType returnValue = null; string scalarTypeName = scalarType.Name; foreach (PrimitiveType primitiveType in providerManifest.GetStoreTypes()) { if (primitiveType.Name == scalarTypeName) { returnValue = primitiveType; break; } } Debug.Assert(scalarType != null, "Som scalar type should always resolve to a primitive type"); return returnValue; } // This will update the sentinel values in the facets if required private static void UpdateSentinelValuesInFacets(ref TypeUsage typeUsage) { // For string and decimal types, replace the sentinel by the max possible value PrimitiveType primitiveType = (PrimitiveType)typeUsage.EdmType; if (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.String || primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Binary) { Facet maxLengthFacet = typeUsage.Facets[EdmProviderManifest.MaxLengthFacetName]; if (Helper.IsUnboundedFacetValue(maxLengthFacet)) { typeUsage = typeUsage.ShallowCopy( new FacetValues{ MaxLength = Helper.GetFacet(primitiveType.FacetDescriptions, EdmProviderManifest.MaxLengthFacetName).MaxValue }); } } } ////// Get the type usage for a structured primitive property when converting a CSDL schema /// /// Som Property that contains the type for which we need to get the mapping provider type /// The item collection for currently existing metadata objects private static TypeUsage GetCsdlPrimitiveTypeUsageWithFacets(Som.StructuredProperty somProperty, ConversionCache convertedItemCache) { Debug.Assert(somProperty.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType); // try to get the instance of the primitive type from the item collection so that it back pointer is set. EdmType propertyType = convertedItemCache.ItemCollection.GetItem(somProperty.TypeUsage.EdmType.FullName); TypeUsage typeUsage = null; if (somProperty.CollectionKind != CollectionKind.None) { propertyType = new CollectionType(propertyType); typeUsage = TypeUsage.Create(propertyType); } else { typeUsage = TypeUsage.Create(propertyType); ApplyPrimitiveTypePropertyFacets(somProperty.TypeUsage, ref typeUsage); } return typeUsage; } #endregion #region Nested types /// /// Cache containing item collection and type usages to support looking up and generating /// metadata types. /// private class ConversionCache { #region Fields internal readonly ItemCollection ItemCollection; private readonly Dictionary_nullFacetsTypeUsage; private readonly Dictionary _nullFacetsCollectionTypeUsage; #endregion #region Constructors internal ConversionCache(ItemCollection itemCollection) { this.ItemCollection = itemCollection; this._nullFacetsTypeUsage = new Dictionary (); this._nullFacetsCollectionTypeUsage = new Dictionary (); } #endregion #region Methods /// /// Gets type usage for the given type with null facet values. Caches usage to avoid creating /// redundant type usages. /// internal TypeUsage GetTypeUsageWithNullFacets(EdmType edmType) { // check for cached result TypeUsage result; if (_nullFacetsTypeUsage.TryGetValue(edmType, out result)) { return result; } // construct result result = TypeUsage.Create(edmType, FacetValues.NullFacetValues); // cache result _nullFacetsTypeUsage.Add(edmType, result); return result; } ////// Gets collection type usage for the given type with null facet values. Caches usage to avoid creating /// redundant type usages. /// internal TypeUsage GetCollectionTypeUsageWithNullFacets(EdmType edmType) { // check for cached result TypeUsage result; if (_nullFacetsCollectionTypeUsage.TryGetValue(edmType, out result)) { return result; } // construct collection type from cached element type TypeUsage elementTypeUsage = GetTypeUsageWithNullFacets(edmType); result = TypeUsage.Create(new CollectionType(elementTypeUsage), FacetValues.NullFacetValues); // cache result _nullFacetsCollectionTypeUsage.Add(edmType, result); return result; } #endregion } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....],[....] //--------------------------------------------------------------------- using Som = System.Data.EntityModel.SchemaObjectModel; using System.Data.Common; using System.Diagnostics; using System.Data.Objects.DataClasses; using System.Collections.Generic; using System.Globalization; using System.Text; using System.Linq; namespace System.Data.Metadata.Edm { ////// Helper Class for converting SOM objects to metadata objects /// This class should go away once we have completely integrated SOM and metadata /// internal static class Converter { #region Constructor ////// Static constructor for creating FacetDescription objects that we use /// static Converter() { // Create the enum types that we will need EnumType concurrencyModeType = new EnumType(EdmProviderManifest.ConcurrencyModeFacetName, EdmConstants.EdmNamespace, DataSpace.CSpace); foreach (string name in Enum.GetNames(typeof(ConcurrencyMode))) { concurrencyModeType.AddMember(new EnumMember(name)); } EnumType storeGeneratedPatternType = new EnumType(EdmProviderManifest.StoreGeneratedPatternFacetName, EdmConstants.EdmNamespace, DataSpace.CSpace); foreach (string name in Enum.GetNames(typeof(StoreGeneratedPattern))) { storeGeneratedPatternType.AddMember(new EnumMember(name)); } // Now create the facet description objects ConcurrencyModeFacet = new FacetDescription(EdmProviderManifest.ConcurrencyModeFacetName, concurrencyModeType, null, null, ConcurrencyMode.None); StoreGeneratedPatternFacet = new FacetDescription(EdmProviderManifest.StoreGeneratedPatternFacetName, storeGeneratedPatternType, null, null, StoreGeneratedPattern.None); CollationFacet = new FacetDescription(EdmProviderManifest.CollationFacetName, MetadataItem.EdmProviderManifest.GetPrimitiveType(PrimitiveTypeKind.String), null, null, string.Empty); } #endregion #region Fields internal static readonly FacetDescription ConcurrencyModeFacet; internal static readonly FacetDescription StoreGeneratedPatternFacet; internal static readonly FacetDescription CollationFacet; #endregion #region Methods ////// Converts a schema from SOM into Metadata /// /// The SOM schema to convert /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects internal static IEnumerableConvertSchema(Som.Schema somSchema, DbProviderManifest providerManifest, ItemCollection itemCollection) { Dictionary newGlobalItems = new Dictionary (); ConvertSchema(somSchema, providerManifest, new ConversionCache(itemCollection), newGlobalItems); return newGlobalItems.Values; } internal static IEnumerable ConvertSchema(IList somSchemas, DbProviderManifest providerManifest, ItemCollection itemCollection) { Dictionary newGlobalItems = new Dictionary (); ConversionCache conversionCache = new ConversionCache(itemCollection); foreach (Som.Schema somSchema in somSchemas) { ConvertSchema(somSchema, providerManifest, conversionCache, newGlobalItems); } return newGlobalItems.Values; } private static void ConvertSchema(Som.Schema somSchema, DbProviderManifest providerManifest, ConversionCache convertedItemCache, Dictionary newGlobalItems) { foreach (Som.SchemaType element in somSchema.SchemaTypes) { LoadSchemaElement(element, providerManifest, convertedItemCache, newGlobalItems); } foreach (Som.SchemaEntityType element in somSchema.SchemaTypes.OfType ()) { LoadEntityTypePhase2(element, providerManifest, convertedItemCache, newGlobalItems); } if (convertedItemCache.ItemCollection.DataSpace == DataSpace.CSpace) { EdmItemCollection edmCollection = (EdmItemCollection)convertedItemCache.ItemCollection; //Get the version of the SomSchema and update the EdmVersion to be the Maximum of all the //versions of the schemas that are being loaded in this item collection. edmCollection.EdmVersion = Math.Max(somSchema.EdmVersion, edmCollection.EdmVersion); } } /// /// Loads a schema element /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The item resulting from the load private static MetadataItem LoadSchemaElement(Som.SchemaType element, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { // Try to fetch from the collection first GlobalItem item; Debug.Assert(!convertedItemCache.ItemCollection.TryGetValue(element.FQName, false, out item), "Som should have checked for duplicate items"); // Try to fetch in our collection of new GlobalItems if (newGlobalItems.TryGetValue(element, out item)) { return item; } Som.EntityContainer entityContainer = element as Som.EntityContainer; // Perform different conversion depending on the type of the SOM object if (entityContainer!=null) { item = ConvertToEntityContainer(entityContainer, providerManifest, convertedItemCache, newGlobalItems); } else if (element is Som.SchemaEntityType) { item = ConvertToEntityType((Som.SchemaEntityType)element, providerManifest, convertedItemCache, newGlobalItems); } else if (element is Som.Relationship) { item = ConvertToAssociationType((Som.Relationship)element, providerManifest, convertedItemCache, newGlobalItems); } else if (element is Som.SchemaComplexType) { item = ConvertToComplexType((Som.SchemaComplexType)element, providerManifest, convertedItemCache, newGlobalItems); } else if (element is Som.Function) { item = ConvertToFunction((Som.Function)element, providerManifest, convertedItemCache, null, newGlobalItems); } else { // the only type we don't handle is the ProviderManifest TypeElement // if it is anything else, it is probably a mistake Debug.Assert(element is Som.TypeElement && element.Schema.DataModel == Som.SchemaDataModelOption.ProviderManifestModel, "Unknown Type in somschema"); return null; } return item; } /// /// Converts an entity container from SOM to metadata /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The entity container object resulting from the convert private static EntityContainer ConvertToEntityContainer(Som.EntityContainer element, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { // Creating a new entity container object and populate with converted entity set objects EntityContainer entityContainer = new EntityContainer(element.Name, GetDataSpace(providerManifest)); newGlobalItems.Add(element, entityContainer); foreach (Som.EntityContainerEntitySet entitySet in element.EntitySets) { entityContainer.AddEntitySetBase(ConvertToEntitySet(entitySet, entityContainer.Name, providerManifest, convertedItemCache, newGlobalItems)); } // Populate with converted relationship set objects foreach (Som.EntityContainerRelationshipSet relationshipSet in element.RelationshipSets) { Debug.Assert(relationshipSet.Relationship.RelationshipKind == RelationshipKind.Association, "We do not support containment set"); entityContainer.AddEntitySetBase(ConvertToAssociationSet(relationshipSet, providerManifest, convertedItemCache, entityContainer, newGlobalItems)); } // Populate with converted function imports foreach (Som.Function functionImport in element.FunctionImports) { entityContainer.AddFunctionImport(ConvertToFunction(functionImport, providerManifest, convertedItemCache, entityContainer, newGlobalItems)); } // Extract the optional Documentation if (element.Documentation != null) { entityContainer.Documentation = ConvertToDocumentation(element.Documentation); } AddOtherContent(element, entityContainer); return entityContainer; } /// /// Converts an entity type from SOM to metadata /// /// This method should only build the internally contained and vertical part of the EntityType (keys, properties, and base types) but not /// sideways parts (NavigationProperties) that go between types or we risk trying to access and EntityTypes keys, from the referenctial constraint, /// before the base type, which has the keys, is setup yet. /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The entity type object resulting from the convert private static EntityType ConvertToEntityType(Som.SchemaEntityType element, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { string[] keyMembers = null; // Check if this type has keys if (element.DeclaredKeyProperties.Count != 0) { keyMembers = new string[element.DeclaredKeyProperties.Count]; for (int i = 0; i < keyMembers.Length; i++) { //Add the name of the key property to the list of //key properties keyMembers[i] = (element.DeclaredKeyProperties[i].Property.Name); } } EdmProperty[] properties = new EdmProperty[element.Properties.Count]; int index = 0; foreach (Som.StructuredProperty somProperty in element.Properties) { properties[index++] = ConvertToProperty(somProperty, providerManifest, convertedItemCache, newGlobalItems); } EntityType entityType = new EntityType(element.Name, element.Namespace, GetDataSpace(providerManifest), keyMembers, properties); if (element.BaseType != null) { entityType.BaseType = (EdmType)(LoadSchemaElement(element.BaseType, providerManifest, convertedItemCache, newGlobalItems)); } // set the abstract and sealed type values for the entity type entityType.Abstract = element.IsAbstract; // Extract the optional Documentation if (element.Documentation != null) { entityType.Documentation = ConvertToDocumentation(element.Documentation); } AddOtherContent(element, entityType); newGlobalItems.Add(element, entityType); return entityType; } private static void LoadEntityTypePhase2(Som.SchemaEntityType element, DbProviderManifest providerManifest, ConversionCache convertedItemCache, Dictionary newGlobalItems) { EntityType entityType = (EntityType)newGlobalItems[element]; // Since Navigation properties are internal and not part of member collection, we // need to initialize the base class first before we start adding the navigation property // this will ensure that all the base navigation properties are initialized foreach (Som.NavigationProperty somNavigationProperty in element.NavigationProperties) { entityType.AddMember(ConvertToNavigationProperty(entityType, somNavigationProperty, providerManifest, convertedItemCache, newGlobalItems)); } } /// /// Converts an complex type from SOM to metadata /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The complex type object resulting from the convert private static ComplexType ConvertToComplexType(Som.SchemaComplexType element, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { ComplexType complexType = new ComplexType(element.Name, element.Namespace, GetDataSpace(providerManifest)); newGlobalItems.Add(element, complexType); foreach (Som.StructuredProperty somProperty in element.Properties) { complexType.AddMember(ConvertToProperty(somProperty, providerManifest, convertedItemCache, newGlobalItems)); } // set the abstract and sealed type values for the entity type complexType.Abstract = element.IsAbstract; if (element.BaseType != null) { complexType.BaseType = (EdmType)(LoadSchemaElement(element.BaseType, providerManifest, convertedItemCache, newGlobalItems)); } // Extract the optional Documentation if (element.Documentation != null) { complexType.Documentation = ConvertToDocumentation(element.Documentation); } AddOtherContent(element, complexType); return complexType; } /// /// Converts an association type from SOM to metadata /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The association type object resulting from the convert private static AssociationType ConvertToAssociationType(Som.Relationship element, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { Debug.Assert(element.RelationshipKind == RelationshipKind.Association); AssociationType associationType = new AssociationType(element.Name, element.Namespace, GetDataSpace(providerManifest)); newGlobalItems.Add(element, associationType); foreach (Som.RelationshipEnd end in element.Ends) { Som.SchemaType entityTypeElement = end.Type; EntityType endEntityType = (EntityType)LoadSchemaElement(entityTypeElement, providerManifest, convertedItemCache, newGlobalItems); AssociationEndMember endMember = InitializeAssociationEndMember(associationType, end, endEntityType); AddOtherContent(end, endMember); // Loop through and convert the operations foreach (Som.OnOperation operation in end.Operations) { // Process only the ones that we recognize if (operation.Operation != Som.Operation.Delete) { continue; } // Determine the action for this operation OperationAction action = OperationAction.None; switch (operation.Action) { case Som.Action.Cascade: action = OperationAction.Cascade; break; case Som.Action.None: action = OperationAction.None; break; default: throw EntityUtil.OperationActionNotSupported(); } endMember.DeleteBehavior = action; } // Extract optional Documentation hanging off the end element if (end.Documentation != null) { endMember.Documentation = ConvertToDocumentation(end.Documentation); } } Debug.Assert(associationType.ReferentialConstraints.Count == 0, "This must never have been initialized"); for (int i = 0; i < element.Constraints.Count; i++) { Som.ReferentialConstraint constraint = element.Constraints[i]; AssociationEndMember fromMember = (AssociationEndMember) associationType.Members[constraint.PrincipalRole.Name]; AssociationEndMember toMember = (AssociationEndMember)associationType.Members[constraint.DependentRole.Name]; EntityTypeBase fromEntityType = ((RefType)fromMember.TypeUsage.EdmType).ElementType; EntityTypeBase toEntityType = ((RefType)toMember.TypeUsage.EdmType).ElementType; ReferentialConstraint referentialConstraint = new ReferentialConstraint(fromMember, toMember, GetProperties(fromEntityType, constraint.PrincipalRole.RoleProperties), GetProperties(toEntityType, constraint.DependentRole.RoleProperties)); // Attach the optional Documentation if (constraint.Documentation != null) referentialConstraint.Documentation = ConvertToDocumentation(constraint.Documentation); if (fromMember.Documentation != null) referentialConstraint.FromRole.Documentation = ConvertToDocumentation(constraint.PrincipalRole.Documentation); if (toMember.Documentation != null) referentialConstraint.ToRole.Documentation = ConvertToDocumentation(constraint.DependentRole.Documentation); associationType.AddReferentialConstraint(referentialConstraint); AddOtherContent(element.Constraints[i], referentialConstraint); } // Extract the optional Documentation if (element.Documentation != null) { associationType.Documentation = ConvertToDocumentation(element.Documentation); } AddOtherContent(element, associationType); return associationType; } /// /// Initialize the end member if its not initialized already /// /// /// /// private static AssociationEndMember InitializeAssociationEndMember(AssociationType associationType, Som.IRelationshipEnd end, EntityType endMemberType) { AssociationEndMember associationEnd; EdmMember member; // make sure that the end is not initialized as of yet if (!associationType.Members.TryGetValue(end.Name, false/*ignoreCase*/, out member)) { // Create the end member and add the operations associationEnd = new AssociationEndMember(end.Name, endMemberType.GetReferenceType(), end.Multiplicity); associationType.AddKeyMember(associationEnd); } else { associationEnd = (AssociationEndMember)member; } //Extract the optional Documentation Som.RelationshipEnd relationshipEnd = end as Som.RelationshipEnd; if (relationshipEnd != null && (relationshipEnd.Documentation != null)) { associationEnd.Documentation = ConvertToDocumentation(relationshipEnd.Documentation); } return associationEnd; } private static EdmProperty[] GetProperties(EntityTypeBase entityType, IListproperties) { Debug.Assert(properties.Count != 0); EdmProperty[] result = new EdmProperty[properties.Count]; for (int i = 0; i < properties.Count; i++) { result[i] = (EdmProperty) entityType.Members[properties[i].Name]; } return result; } private static void AddOtherContent(Som.SchemaElement element, MetadataItem item) { if (element.OtherContent.Count > 0) { item.AddMetadataProperties(element.OtherContent); } } /// /// Converts an entity set from SOM to metadata /// /// The SOM element to process /// the name of the container this will be added to /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The entity set object resulting from the convert private static EntitySet ConvertToEntitySet(Som.EntityContainerEntitySet set, string containerName, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { EntitySet entitySet = new EntitySet(set.Name,set.DbSchema,set.Table, set.DefiningQuery, (EntityType)LoadSchemaElement(set.EntityType, providerManifest, convertedItemCache, newGlobalItems)); // Extract the optional Documentation if (set.Documentation != null) { entitySet.Documentation = ConvertToDocumentation(set.Documentation); } AddOtherContent(set, entitySet); return entitySet; } /// /// Converts an entity set from SOM to metadata /// /// The SOM element to process /// ///The entity set object resulting from the convert private static EntitySet GetEntitySet(Som.EntityContainerEntitySet set, EntityContainer container) { return container.GetEntitySetByName(set.Name, false); } ////// Converts an association set from SOM to metadata /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion /// ///The association set object resulting from the convert private static AssociationSet ConvertToAssociationSet(Som.EntityContainerRelationshipSet relationshipSet, DbProviderManifest providerManifest, ConversionCache convertedItemCache, EntityContainer container, DictionarynewGlobalItems) { Debug.Assert(relationshipSet.Relationship.RelationshipKind == RelationshipKind.Association); AssociationType associationType = (AssociationType)LoadSchemaElement((Som.SchemaType)relationshipSet.Relationship, providerManifest, convertedItemCache, newGlobalItems); AssociationSet associationSet = new AssociationSet(relationshipSet.Name, associationType); foreach (Som.EntityContainerRelationshipSetEnd end in relationshipSet.Ends) { //-- need the EntityType for the end EntityType endEntityType = (EntityType)LoadSchemaElement(end.EntitySet.EntityType, providerManifest, convertedItemCache, newGlobalItems); //-- need to get the end member AssociationEndMember endMember = (AssociationEndMember) associationType.Members[end.Name]; //-- create the end AssociationSetEnd associationSetEnd = new AssociationSetEnd(GetEntitySet(end.EntitySet, container), associationSet, endMember); AddOtherContent(end, associationSetEnd); associationSet.AddAssociationSetEnd(associationSetEnd); // Extract optional Documentation hanging off the end element if (end.Documentation != null) { associationSetEnd.Documentation = ConvertToDocumentation(end.Documentation); } } // Extract the optional Documentation if (relationshipSet.Documentation != null) { associationSet.Documentation = ConvertToDocumentation(relationshipSet.Documentation); } AddOtherContent(relationshipSet, associationSet); return associationSet; } /// /// Converts a property from SOM to metadata /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The property object resulting from the convert private static EdmProperty ConvertToProperty(Som.StructuredProperty somProperty, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { EdmProperty property; // Get the appropriate type object for this type, for primitive types, get the facet values for the primitive type // property as a type usage object as well TypeUsage typeUsage = null; Som.ScalarType scalarType = somProperty.Type as Som.ScalarType; if (scalarType != null) { if (somProperty.Schema.DataModel == Som.SchemaDataModelOption.EntityDataModel) { // csdl typeUsage = GetCsdlPrimitiveTypeUsageWithFacets(somProperty, convertedItemCache); } else { // parsing ssdl typeUsage = somProperty.TypeUsage; UpdateSentinelValuesInFacets(ref typeUsage); } } else { EdmType propertyType = (EdmType)LoadSchemaElement(somProperty.Type, providerManifest, convertedItemCache, newGlobalItems); if (somProperty.CollectionKind != CollectionKind.None) { propertyType = new CollectionType(propertyType); } typeUsage = TypeUsage.Create(propertyType); } PopulateGeneralFacets(somProperty, providerManifest, ref typeUsage); property = new EdmProperty(somProperty.Name, typeUsage); // Extract the optional Documentation if (somProperty.Documentation != null) { property.Documentation = ConvertToDocumentation(somProperty.Documentation); } AddOtherContent(somProperty, property); return property; } /// /// Converts a navigation property from SOM to metadata /// /// entity type on which this navigation property was declared /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The property object resulting from the convert private static NavigationProperty ConvertToNavigationProperty(EntityType declaringEntityType, Som.NavigationProperty somNavigationProperty, DbProviderManifest providerManifest, ConversionCache convertedItemCache, DictionarynewGlobalItems) { // Navigation properties cannot be primitive types, so we can ignore the possibility of having primitive type // facets EntityType toEndEntityType = (EntityType)LoadSchemaElement(somNavigationProperty.Type, providerManifest, convertedItemCache, newGlobalItems); EdmType edmType = toEndEntityType; // Also load the relationship Type that this navigation property represents AssociationType relationshipType = (AssociationType)LoadSchemaElement((Som.Relationship)somNavigationProperty.Relationship, providerManifest, convertedItemCache, newGlobalItems); Som.IRelationshipEnd somRelationshipEnd = null; somNavigationProperty.Relationship.TryGetEnd(somNavigationProperty.ToEnd.Name, out somRelationshipEnd); if (somRelationshipEnd.Multiplicity == RelationshipMultiplicity.Many) { edmType = toEndEntityType.GetCollectionType(); } else { Debug.Assert(somRelationshipEnd.Multiplicity != RelationshipMultiplicity.Many); edmType = toEndEntityType; } TypeUsage typeUsage; if (somRelationshipEnd.Multiplicity == RelationshipMultiplicity.One) { typeUsage = TypeUsage.Create(edmType, new FacetValues{Nullable = false}); } else { typeUsage = TypeUsage.Create(edmType); } // We need to make sure that both the ends of the relationtype are initialized. If there are not, then we should // initialize them here InitializeAssociationEndMember(relationshipType, somNavigationProperty.ToEnd, toEndEntityType); InitializeAssociationEndMember(relationshipType, somNavigationProperty.FromEnd, declaringEntityType); // The type of the navigation property must be a ref or collection depending on which end they belong to NavigationProperty navigationProperty = new NavigationProperty(somNavigationProperty.Name, typeUsage); navigationProperty.RelationshipType = relationshipType; navigationProperty.ToEndMember = (RelationshipEndMember)relationshipType.Members[somNavigationProperty.ToEnd.Name]; navigationProperty.FromEndMember = (RelationshipEndMember)relationshipType.Members[somNavigationProperty.FromEnd.Name]; // Extract the optional Documentation if (somNavigationProperty.Documentation != null) { navigationProperty.Documentation = ConvertToDocumentation(somNavigationProperty.Documentation); } AddOtherContent(somNavigationProperty, navigationProperty); return navigationProperty; } /// /// Converts a function from SOM to metadata /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// For function imports, the entity container including the function declaration /// The new GlobalItem objects that are created as a result of this conversion ///The function object resulting from the convert private static EdmFunction ConvertToFunction(Som.Function somFunction, DbProviderManifest providerManifest, ConversionCache convertedItemCache, EntityContainer entityContainer, DictionarynewGlobalItems) { // If we already have it, don't bother converting GlobalItem globalItem = null; // if we are converted the function import, we need not check the global items collection, // since the function imports are local to the entity container if (!somFunction.IsFunctionImport && newGlobalItems.TryGetValue(somFunction, out globalItem)) { return (EdmFunction)globalItem; } FunctionParameter returnParameter = null; bool areConvertingForProviderManifest = somFunction.Schema.DataModel == Som.SchemaDataModelOption.ProviderManifestModel; TypeUsage returnType = GetFunctionTypeUsage(somFunction.ReturnType, providerManifest, areConvertingForProviderManifest, somFunction.Type, somFunction.CollectionKind, somFunction, convertedItemCache, newGlobalItems); if (null != returnType) { // Create the return parameter object, need to set the declaring type explicitly on the return parameter // because we aren't adding it to the members collection returnParameter = new FunctionParameter(EdmConstants.ReturnType, returnType, ParameterMode.ReturnValue); } EntitySet entitySet = null; if (null != somFunction.EntitySet) { Debug.Assert(null != entityContainer, "only function imports may declare a entity set " + "and function imports are always scoped to an entity container"); entitySet = GetEntitySet(somFunction.EntitySet, entityContainer); } List parameters = new List (); foreach (Som.Parameter somParameter in somFunction.Parameters) { TypeUsage parameterType = GetFunctionTypeUsage(somParameter, providerManifest, areConvertingForProviderManifest, somParameter.Type, somParameter.CollectionKind, somParameter, convertedItemCache, newGlobalItems); FunctionParameter parameter = new FunctionParameter(somParameter.Name, parameterType, GetParameterMode(somParameter.ParameterDirection)); AddOtherContent(somParameter, parameter); if (somParameter.Documentation != null) { parameter.Documentation = ConvertToDocumentation(somParameter.Documentation); } parameters.Add(parameter); } EdmFunction function = new EdmFunction(somFunction.Name, somFunction.Schema.Namespace, GetDataSpace(providerManifest), new EdmFunctionPayload { Schema = somFunction.DbSchema, StoreFunctionName = somFunction.StoreFunctionName, CommandText = somFunction.CommandText, EntitySet = entitySet, IsAggregate = somFunction.IsAggregate, IsBuiltIn = somFunction.IsBuiltIn, IsNiladic = somFunction.IsNiladicFunction, IsComposable = somFunction.IsComposable, IsFromProviderManifest = areConvertingForProviderManifest, ReturnParameter = returnParameter, Parameters = parameters.ToArray(), ParameterTypeSemantics = somFunction.ParameterTypeSemantics, }); // Add this function to new global items, only if it is not a function import if (!somFunction.IsFunctionImport) { newGlobalItems.Add(somFunction, function); } //Check if we already converted functions since we are loading it from //ssdl we could see functions many times. GlobalItem returnFunction = null; Debug.Assert(!convertedItemCache.ItemCollection.TryGetValue(function.Identity, false, out returnFunction), "Function duplicates must be checked by som"); // Extract the optional Documentation if (somFunction.Documentation != null) { function.Documentation = ConvertToDocumentation(somFunction.Documentation); } AddOtherContent(somFunction, function); return function; } /// /// Converts an SOM Documentation node to a metadata Documentation construct /// /// The SOM element to process /// The provider manifest to be used for conversion /// The item collection for currently existing metadata objects /// The new GlobalItem objects that are created as a result of this conversion ///The Do----mentation object resulting from the convert operation private static Documentation ConvertToDocumentation(Som.DocumentationElement element) { Debug.Assert(null != element, "ConvertToDocumentation cannot be invoked with a null Som.Documentation element"); return element.MetadataDocumentation; } private static TypeUsage GetFunctionTypeUsage(Som.FacetEnabledSchemaElement somParameter, DbProviderManifest providerManifest, bool areConvertingForProviderManifest, Som.SchemaType type, CollectionKind collectionKind, Som.SchemaElement schemaElement, ConversionCache convertedItemCache, DictionarynewGlobalItems) { if (null != somParameter && somParameter.HasUserDefinedFacets) { return somParameter.TypeUsage; } if (null == type) { return null; } EdmType edmType; if (!areConvertingForProviderManifest) { // SOM verifies the type is either scalar, row, or entity Som.ScalarType scalarType = type as Som.ScalarType; if (null != scalarType) { edmType = GetSsdlPrimitiveType(scalarType, providerManifest); } else { edmType = (EdmType)LoadSchemaElement(type, providerManifest, convertedItemCache, newGlobalItems); } } else if (type is Som.TypeElement) { Som.TypeElement typeElement = type as Som.TypeElement; edmType = typeElement.PrimitiveType; } else { Som.ScalarType typeElement = type as Som.ScalarType; edmType = typeElement.Type; } TypeUsage usage; if (collectionKind != CollectionKind.None) { usage = convertedItemCache.GetCollectionTypeUsageWithNullFacets(edmType); } else { usage = convertedItemCache.GetTypeUsageWithNullFacets(edmType); } return usage; } /// /// Converts the ParameterDirection into a ParameterMode /// /// The ParameterDirection to convert ///ParameterMode private static ParameterMode GetParameterMode(ParameterDirection parameterDirection) { switch (parameterDirection) { case ParameterDirection.Input: return ParameterMode.In; case ParameterDirection.Output: return ParameterMode.Out; case ParameterDirection.InputOutput: return ParameterMode.InOut; default: throw EntityUtil.MetadataGeneralError(); } } ////// Apply the facet values from the property which are specific to primitive types to the given list of facets /// /// The source TypeUsage /// The PrimativeType of the target private static void ApplyPrimitiveTypePropertyFacets(TypeUsage sourceType, ref TypeUsage targetType) { DictionarynewFacets = targetType.Facets.ToDictionary(f => f.Name); bool madeChange = false; foreach (Facet sourceFacet in sourceType.Facets) { Facet targetFacet; if(newFacets.TryGetValue(sourceFacet.Name, out targetFacet)) { if (!targetFacet.Description.IsConstant) { madeChange = true; newFacets[targetFacet.Name] = Facet.Create(targetFacet.Description, sourceFacet.Value); } } else { madeChange = true; newFacets.Add(sourceFacet.Name, sourceFacet); } } if (madeChange) { targetType = TypeUsage.Create(targetType.EdmType, newFacets.Values); } } /// /// Populate the facets on the TypeUsage object fora property /// /// The property containing the information /// The type usage object where to populate facet /// The provider manifest to be used for conversion private static void PopulateGeneralFacets(Som.StructuredProperty somProperty, DbProviderManifest providerManifest, ref TypeUsage propertyTypeUsage) { bool madeChanges = false; Dictionaryfacets = propertyTypeUsage.Facets.ToDictionary(f => f.Name); if (!somProperty.Nullable) { facets[DbProviderManifest.NullableFacetName] = Facet.Create(MetadataItem.NullableFacetDescription, false); madeChanges = true; } if (somProperty.Default != null) { facets[DbProviderManifest.DefaultValueFacetName] = Facet.Create(MetadataItem.DefaultValueFacetDescription, somProperty.DefaultAsObject); madeChanges = true; } //This is not really a general facet //If we are dealing with a 1.1 Schema, Add a facet for CollectionKind if (somProperty.Schema.EdmVersion == XmlConstants.EdmVersionForV1_1) { Facet newFacet = Facet.Create(MetadataItem.CollectionKindFacetDescription, somProperty.CollectionKind); facets.Add(newFacet.Name, newFacet); madeChanges = true; } if (madeChanges) { propertyTypeUsage = TypeUsage.Create(propertyTypeUsage.EdmType, facets.Values); } } private static DataSpace GetDataSpace(DbProviderManifest providerManifest) { // Target attributes is for types and sets in target space. if (providerManifest is EdmProviderManifest) { return DataSpace.CSpace; } else { return DataSpace.SSpace; } } /// /// Get a primitive type when converting a CSDL schema /// /// The schema type representing the primitive type /// The provider manifest for retrieving the store types private static PrimitiveType GetSsdlPrimitiveType(Som.ScalarType scalarType, DbProviderManifest providerManifest) { PrimitiveType returnValue = null; string scalarTypeName = scalarType.Name; foreach (PrimitiveType primitiveType in providerManifest.GetStoreTypes()) { if (primitiveType.Name == scalarTypeName) { returnValue = primitiveType; break; } } Debug.Assert(scalarType != null, "Som scalar type should always resolve to a primitive type"); return returnValue; } // This will update the sentinel values in the facets if required private static void UpdateSentinelValuesInFacets(ref TypeUsage typeUsage) { // For string and decimal types, replace the sentinel by the max possible value PrimitiveType primitiveType = (PrimitiveType)typeUsage.EdmType; if (primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.String || primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Binary) { Facet maxLengthFacet = typeUsage.Facets[EdmProviderManifest.MaxLengthFacetName]; if (Helper.IsUnboundedFacetValue(maxLengthFacet)) { typeUsage = typeUsage.ShallowCopy( new FacetValues{ MaxLength = Helper.GetFacet(primitiveType.FacetDescriptions, EdmProviderManifest.MaxLengthFacetName).MaxValue }); } } } ////// Get the type usage for a structured primitive property when converting a CSDL schema /// /// Som Property that contains the type for which we need to get the mapping provider type /// The item collection for currently existing metadata objects private static TypeUsage GetCsdlPrimitiveTypeUsageWithFacets(Som.StructuredProperty somProperty, ConversionCache convertedItemCache) { Debug.Assert(somProperty.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType); // try to get the instance of the primitive type from the item collection so that it back pointer is set. EdmType propertyType = convertedItemCache.ItemCollection.GetItem(somProperty.TypeUsage.EdmType.FullName); TypeUsage typeUsage = null; if (somProperty.CollectionKind != CollectionKind.None) { propertyType = new CollectionType(propertyType); typeUsage = TypeUsage.Create(propertyType); } else { typeUsage = TypeUsage.Create(propertyType); ApplyPrimitiveTypePropertyFacets(somProperty.TypeUsage, ref typeUsage); } return typeUsage; } #endregion #region Nested types /// /// Cache containing item collection and type usages to support looking up and generating /// metadata types. /// private class ConversionCache { #region Fields internal readonly ItemCollection ItemCollection; private readonly Dictionary_nullFacetsTypeUsage; private readonly Dictionary _nullFacetsCollectionTypeUsage; #endregion #region Constructors internal ConversionCache(ItemCollection itemCollection) { this.ItemCollection = itemCollection; this._nullFacetsTypeUsage = new Dictionary (); this._nullFacetsCollectionTypeUsage = new Dictionary (); } #endregion #region Methods /// /// Gets type usage for the given type with null facet values. Caches usage to avoid creating /// redundant type usages. /// internal TypeUsage GetTypeUsageWithNullFacets(EdmType edmType) { // check for cached result TypeUsage result; if (_nullFacetsTypeUsage.TryGetValue(edmType, out result)) { return result; } // construct result result = TypeUsage.Create(edmType, FacetValues.NullFacetValues); // cache result _nullFacetsTypeUsage.Add(edmType, result); return result; } ////// Gets collection type usage for the given type with null facet values. Caches usage to avoid creating /// redundant type usages. /// internal TypeUsage GetCollectionTypeUsageWithNullFacets(EdmType edmType) { // check for cached result TypeUsage result; if (_nullFacetsCollectionTypeUsage.TryGetValue(edmType, out result)) { return result; } // construct collection type from cached element type TypeUsage elementTypeUsage = GetTypeUsageWithNullFacets(edmType); result = TypeUsage.Create(new CollectionType(elementTypeUsage), FacetValues.NullFacetValues); // cache result _nullFacetsCollectionTypeUsage.Add(edmType, result); return result; } #endregion } #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ReadingWritingEntityEventArgs.cs
- ArgumentNullException.cs
- SafeNativeMethods.cs
- MessageSmuggler.cs
- WebBrowserBase.cs
- DataGridViewRowHeaderCell.cs
- ExpandoObject.cs
- KeyValuePairs.cs
- PersonalizableAttribute.cs
- EntitySqlQueryBuilder.cs
- TypeElement.cs
- CustomBindingElement.cs
- DataGridViewCellFormattingEventArgs.cs
- AutoGeneratedFieldProperties.cs
- SettingsProperty.cs
- HttpCapabilitiesEvaluator.cs
- LocatorBase.cs
- CodeCatchClauseCollection.cs
- ItemCollection.cs
- Stopwatch.cs
- UnmanagedMemoryStreamWrapper.cs
- OdbcConnectionStringbuilder.cs
- IconHelper.cs
- BaseCollection.cs
- AppSettingsExpressionEditor.cs
- AssemblyBuilder.cs
- MostlySingletonList.cs
- DefaultDialogButtons.cs
- smtpconnection.cs
- MemberPathMap.cs
- ToolboxComponentsCreatingEventArgs.cs
- ListComponentEditorPage.cs
- BamlLocalizer.cs
- DbExpressionVisitor.cs
- SystemIcons.cs
- EllipseGeometry.cs
- WebPartConnectVerb.cs
- ImageMapEventArgs.cs
- Model3D.cs
- Context.cs
- XmlDocument.cs
- DisplayInformation.cs
- BadImageFormatException.cs
- InstanceDataCollection.cs
- SecurityElement.cs
- BulletChrome.cs
- ToolStripArrowRenderEventArgs.cs
- _ListenerAsyncResult.cs
- XmlAggregates.cs
- SQLStringStorage.cs
- SqlAggregateChecker.cs
- DataGridState.cs
- StylusPointProperty.cs
- NamedPipeConnectionPoolSettingsElement.cs
- UniqueConstraint.cs
- SystemDropShadowChrome.cs
- EncodingInfo.cs
- PenLineJoinValidation.cs
- StrokeIntersection.cs
- RepeaterItem.cs
- DataKey.cs
- FileNameEditor.cs
- Parameter.cs
- Rijndael.cs
- DataControlFieldCell.cs
- InputLanguageEventArgs.cs
- PolygonHotSpot.cs
- DataKeyCollection.cs
- XmlHierarchicalDataSourceView.cs
- QilUnary.cs
- MouseGestureConverter.cs
- DirectoryObjectSecurity.cs
- IdnElement.cs
- TreeNodeMouseHoverEvent.cs
- nulltextcontainer.cs
- UdpSocket.cs
- UnsafeNativeMethodsTablet.cs
- NullReferenceException.cs
- Geometry3D.cs
- FigureHelper.cs
- SByteStorage.cs
- WebServiceErrorEvent.cs
- ImageKeyConverter.cs
- SelfIssuedAuthRSAPKCS1SignatureFormatter.cs
- AutoGeneratedFieldProperties.cs
- ControlBindingsCollection.cs
- EntryPointNotFoundException.cs
- PropVariant.cs
- XmlObjectSerializerWriteContextComplexJson.cs
- DataSvcMapFile.cs
- SemanticResolver.cs
- RenderData.cs
- PerfCounters.cs
- CharEnumerator.cs
- Repeater.cs
- HttpModuleCollection.cs
- SimplePropertyEntry.cs
- HtmlInputText.cs
- WindowsStartMenu.cs
- InfoCardKeyedHashAlgorithm.cs