//--------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System; using System.Data.Common; using System.Collections.Generic; using System.Text; using System.Data.Metadata.Edm; using System.Reflection; using System.Diagnostics; using System.Xml; using System.Globalization; using System.IO; using System.Data.Entity.Design.SsdlGenerator; using System.Linq; namespace System.Data.Entity.Design.Common { /// /// This class is reponsible for serailizing Edm Metadata out to the appropriate file .csdl or .ssdl /// internal class MetadataItemSerializer { public static readonly EdmType NoSpecificTypeSentinal = MetadataItem.GetBuiltInType(BuiltInTypeKind.EdmType); private bool _isModel; private ErrorsLookup _errorsLookup; private XmlWriter _writer; private Version _schemaVersion; private MetadataItemSerializer(XmlWriter writer, bool isModel, ErrorsLookup errorsLookup, Version schemaVersion) { _writer = writer; _isModel = isModel; _errorsLookup = errorsLookup; _schemaVersion = schemaVersion; } public class ErrorsLookup : Dictionary> { } internal readonly string EdmNamespace = "Edm"; public static void WriteXml(XmlWriter writer, ItemCollection collection, string namespaceToWrite, Version schemaVersion, params KeyValuePair [] xmlPrefixToNamespaces) { WriteXml(writer, collection, namespaceToWrite, new ErrorsLookup(), new List(), null, null, schemaVersion, xmlPrefixToNamespaces); } internal static void WriteXml(XmlWriter writer, ItemCollection collection, string namespaceToWrite, ErrorsLookup errorsLookup, List commentedOutItems, string provider, string providerManifestToken, Version schemaVersion, params KeyValuePair[] xmlPrefixToNamespaces) { Debug.Assert(writer != null, "writer parameter is null"); Debug.Assert(collection != null, "collection parameter is null"); Debug.Assert(errorsLookup != null, "errorsLookup parameter is null"); Debug.Assert(!string.IsNullOrEmpty(namespaceToWrite), "namespaceToWrite parameter is null or empty"); MetadataItemSerializer serializer = new MetadataItemSerializer(writer, collection.DataSpace == DataSpace.CSpace, errorsLookup, schemaVersion); serializer.ValidateNamespace(namespaceToWrite); serializer.WriteSchemaElement(namespaceToWrite, provider, providerManifestToken, xmlPrefixToNamespaces); serializer.WriteErrorsComment(NoSpecificTypeSentinal); foreach (EntityContainer item in collection.GetItems()) { serializer.WriteEntityContainerElement(item); } foreach (EdmType type in collection.GetItems()) { // is it in the right space (c or s) // does it have the right namespace? if (type.NamespaceName == namespaceToWrite) { serializer.WriteTypeElement(type); } } if(commentedOutItems.Count > 0) { StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.OmitXmlDeclaration = true; // we can have more than one commented out type // which will look like multiple root elements, so this is a fragment settings.ConformanceLevel = ConformanceLevel.Fragment; XmlWriter commentWriter = XmlWriter.Create(stringWriter, settings); MetadataItemSerializer commmentSerializer = new MetadataItemSerializer(commentWriter, collection.DataSpace == DataSpace.CSpace, errorsLookup, schemaVersion); foreach (EdmType type in commentedOutItems) { commmentSerializer.WriteTypeElement(type); } commentWriter.Flush(); //This is not the cleanest thing to do but XmlTextWriter //does not allow writing xml comment characters while writing a comment. //and since we know exactly the string we write, this is pretty safe. string comment = RemoveXmlCommentCharacters(stringWriter); writer.WriteComment(comment); } writer.WriteEndElement(); } private static string RemoveXmlCommentCharacters(StringWriter stringWriter) { string comment = stringWriter.GetStringBuilder().ToString(); while (comment.Contains(XmlConstants.XmlCommentStartString)) { comment = comment.Replace(XmlConstants.XmlCommentStartString, String.Empty); } while (comment.Contains(XmlConstants.XmlCommentEndString)) { comment = comment.Replace(XmlConstants.XmlCommentEndString, String.Empty); } return comment; } private void ValidateNamespace(string namespaceToWrite) { if (EdmItemCollection.IsSystemNamespace(MetadataItem.EdmProviderManifest, namespaceToWrite)) { throw EDesignUtil.EdmReservedNamespace(namespaceToWrite); } } private void WriteTypeElement(EdmType type) { WriteErrorsComment(type); switch (type.BuiltInTypeKind) { case BuiltInTypeKind.EntityType: WriteEntityTypeElement((EntityType)type); break; case BuiltInTypeKind.AssociationType: WriteAssociationTypeElement((AssociationType)type); break; case BuiltInTypeKind.EdmFunction: WriteFunctionElement((EdmFunction)type); break; case BuiltInTypeKind.ComplexType: WriteComplexTypeElement((ComplexType)type); break; case BuiltInTypeKind.RowType: WriteRowTypeElement((RowType)type); break; default: throw EDesignUtil.NonSerializableType(type.BuiltInTypeKind); } } private void WriteFunctionElement(EdmFunction function) { _writer.WriteStartElement(function.IsFunctionImport ? XmlConstants.FunctionImport : XmlConstants.Function); _writer.WriteAttributeString(XmlConstants.Name, function.Name); // Write function ReturnType as attribute if possible. bool returnParameterHandled = false; if (function.ReturnParameter != null) { var returnTypeUsage = function.ReturnParameter.TypeUsage; bool collection = returnTypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType; if (collection) { Debug.Assert(_schemaVersion >= EntityFrameworkVersions.Version3, "_schemaVersion >= EntityFrameworkVersions.Version3"); returnTypeUsage = ((CollectionType)returnTypeUsage.EdmType).TypeUsage; } if (TypeSemantics.IsPrimitiveType(returnTypeUsage) || TypeSemantics.IsNominalType(returnTypeUsage)) { string typeName = GetFullName(returnTypeUsage.EdmType); if (collection) { typeName = "Collection(" + typeName + ")"; } _writer.WriteAttributeString(XmlConstants.ReturnType, typeName); returnParameterHandled = true; } } if (!_isModel) { _writer.WriteAttributeString(XmlConstants.AggregateAttribute, GetAttributeValueString(function.AggregateAttribute)); _writer.WriteAttributeString(XmlConstants.BuiltInAttribute, GetAttributeValueString(function.BuiltInAttribute)); _writer.WriteAttributeString(XmlConstants.NiladicFunction, GetAttributeValueString(function.NiladicFunctionAttribute)); _writer.WriteAttributeString(XmlConstants.IsComposable, GetAttributeValueString(function.IsComposableAttribute)); _writer.WriteAttributeString(XmlConstants.ParameterTypeSemantics, GetAttributeValueString(function.ParameterTypeSemanticsAttribute)); } else if (function.IsFunctionImport && function.IsComposableAttribute) { Debug.Assert(_schemaVersion >= EntityFrameworkVersions.Version3, "_schemaVersion >= EntityFrameworkVersions.Version3"); _writer.WriteAttributeString(XmlConstants.IsComposable, GetAttributeValueString(true)); } if (function.StoreFunctionNameAttribute != null) { _writer.WriteAttributeString(XmlConstants.StoreFunctionName, function.StoreFunctionNameAttribute); } if(function.CommandTextAttribute != null) { Debug.Assert(!_isModel, "Serialization of CommandTextAttribute is not supported for CSDL."); _writer.WriteAttributeString(XmlConstants.CommandText, function.CommandTextAttribute); } if (function.Schema != null) { _writer.WriteAttributeString(XmlConstants.Schema, function.Schema); } foreach (FunctionParameter parameter in function.Parameters) { WriteFunctionParameterElement(parameter); } // Write function ReturnType subelement if needed. if (function.ReturnParameter != null && !returnParameterHandled) { // Handle a TVF in s-space: Collection(RowType) if (function.ReturnParameter.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType) { Debug.Assert(_schemaVersion >= EntityFrameworkVersions.Version3 && !_isModel, "_schemaVersion >= EntityFrameworkVersions.Version3 && !_isModel"); var elementType = ((CollectionType)function.ReturnParameter.TypeUsage.EdmType).TypeUsage.EdmType; Debug.Assert(elementType.BuiltInTypeKind == BuiltInTypeKind.RowType, "TVF return type is expected to be Collection(RowType)"); var rowType = (RowType)elementType; _writer.WriteStartElement(XmlConstants.ReturnType); _writer.WriteStartElement(XmlConstants.CollectionType); WriteTypeElement(rowType); _writer.WriteEndElement(); _writer.WriteEndElement(); returnParameterHandled = true; } } Debug.Assert(function.ReturnParameter == null || returnParameterHandled, "ReturnParameter was not handled."); _writer.WriteEndElement(); } private void WriteFunctionParameterElement(FunctionParameter parameter) { _writer.WriteStartElement(XmlConstants.Parameter); _writer.WriteAttributeString(XmlConstants.Name, parameter.Name); _writer.WriteAttributeString(XmlConstants.TypeAttribute, GetFullName(parameter.TypeUsage.EdmType)); if (!_isModel) { _writer.WriteAttributeString(XmlConstants.Mode, GetAttributeValueString(parameter.Mode)); } _writer.WriteEndElement(); } private void WriteComplexTypeElement(ComplexType complexType) { _writer.WriteStartElement(XmlConstants.ComplexType); _writer.WriteAttributeString(XmlConstants.Name, complexType.Name); if (complexType.BaseType != null) { _writer.WriteAttributeString(XmlConstants.BaseType, GetFullName(complexType.BaseType)); } foreach (EdmMember member in complexType.GetDeclaredOnlyMembers()) { WritePropertyElement(member); } _writer.WriteEndElement(); } private void WriteAssociationTypeElement(AssociationType associationType) { _writer.WriteStartElement(XmlConstants.Association); _writer.WriteAttributeString(XmlConstants.Name, associationType.Name); foreach (RelationshipEndMember end in associationType.RelationshipEndMembers) { WriteRelationshipEndElement(end); } foreach (ReferentialConstraint constraint in associationType.ReferentialConstraints) { WriteReferentialConstraintElement(constraint); } _writer.WriteEndElement(); } private void WriteRowTypeElement(RowType rowType) { _writer.WriteStartElement(XmlConstants.RowType); foreach (var property in rowType.Properties) { WritePropertyElement(property); } _writer.WriteEndElement(); } private void WriteReferentialConstraintElement(ReferentialConstraint constraint) { _writer.WriteStartElement(XmlConstants.ReferentialConstraint); WriteReferentialConstraintRoleElement(XmlConstants.PrincipalRole, constraint.FromRole, constraint.FromProperties); WriteReferentialConstraintRoleElement(XmlConstants.DependentRole, constraint.ToRole, constraint.ToProperties); _writer.WriteEndElement(); } private void WriteReferentialConstraintRoleElement(string nodeName, RelationshipEndMember end, IList properties) { // Generate the principal and dependent role nodes _writer.WriteStartElement(nodeName); _writer.WriteAttributeString(XmlConstants.Role, end.Name); for (int i = 0; i < properties.Count; i++) { _writer.WriteStartElement(XmlConstants.PropertyRef); _writer.WriteAttributeString(XmlConstants.Name, properties[i].Name); _writer.WriteEndElement(); } _writer.WriteEndElement(); } private void WriteRelationshipEndElement(RelationshipEndMember end) { _writer.WriteStartElement(XmlConstants.End); _writer.WriteAttributeString(XmlConstants.Role, end.Name); string typeName = GetFullName(((RefType)end.TypeUsage.EdmType).ElementType); _writer.WriteAttributeString(XmlConstants.TypeAttribute, typeName); _writer.WriteAttributeString(XmlConstants.Multiplicity, GetXmlMultiplicity(end.RelationshipMultiplicity)); if (end.DeleteBehavior != OperationAction.None) { WriteOperationActionElement(XmlConstants.OnDelete, end.DeleteBehavior); } _writer.WriteEndElement(); } private void WriteOperationActionElement(string elementName, OperationAction operationAction) { _writer.WriteStartElement(elementName); _writer.WriteAttributeString(XmlConstants.Action, operationAction.ToString()); _writer.WriteEndElement(); } private string GetXmlMultiplicity(RelationshipMultiplicity relationshipMultiplicity) { switch(relationshipMultiplicity) { case RelationshipMultiplicity.Many: return "*"; case RelationshipMultiplicity.One: return "1"; case RelationshipMultiplicity.ZeroOrOne: return "0..1"; default: Debug.Fail("Did you add a new RelationshipMultiplicity?"); return string.Empty; } } private void WriteEntityTypeElement(EntityType entityType) { _writer.WriteStartElement(XmlConstants.EntityType); _writer.WriteAttributeString(XmlConstants.Name, entityType.Name); if (entityType.BaseType != null) { _writer.WriteAttributeString(XmlConstants.BaseType, GetFullName(entityType.BaseType)); } if (entityType.Abstract) { _writer.WriteAttributeString(XmlConstants.Abstract, XmlConstants.True); } if (entityType.KeyMembers.Count != 0 && entityType.KeyMembers[0].DeclaringType == entityType) // they are declared on this entity { _writer.WriteStartElement(XmlConstants.Key); for (int i = 0; i < entityType.KeyMembers.Count; i++) { _writer.WriteStartElement(XmlConstants.PropertyRef); _writer.WriteAttributeString(XmlConstants.Name, entityType.KeyMembers[i].Name); _writer.WriteEndElement(); } _writer.WriteEndElement(); } foreach (EdmProperty member in entityType.GetDeclaredOnlyMembers()) { WritePropertyElement(member); } foreach (NavigationProperty navigationProperty in entityType.NavigationProperties ) { if (navigationProperty.DeclaringType == entityType) { WriteNavigationPropertyElement(navigationProperty); } } _writer.WriteEndElement(); } private void WriteErrorsComment(EdmType type) { List errors; if (_errorsLookup.TryGetValue(type, out errors)) { Debug.Assert(errors.Count > 0, "how did we get an empty errors collection?"); StringBuilder builder = new StringBuilder(); builder.AppendLine(Strings.MetadataItemErrorsFoundDuringGeneration); foreach (EdmSchemaError error in errors) { builder.AppendLine(error.ToString()); } _writer.WriteComment(builder.ToString()); } } private void WriteNavigationPropertyElement(NavigationProperty member) { _writer.WriteStartElement(XmlConstants.NavigationProperty); _writer.WriteAttributeString(XmlConstants.Name, member.Name); _writer.WriteAttributeString(XmlConstants.Relationship, member.RelationshipType.FullName); _writer.WriteAttributeString(XmlConstants.FromRole, member.FromEndMember.Name); _writer.WriteAttributeString(XmlConstants.ToRole, member.ToEndMember.Name); _writer.WriteEndElement(); } private void WritePropertyElement(EdmMember member) { _writer.WriteStartElement(XmlConstants.Property); _writer.WriteAttributeString(XmlConstants.Name, member.Name); _writer.WriteAttributeString(XmlConstants.TypeAttribute, GetTypeName(member.TypeUsage)); WritePropertyTypeFacets(member.TypeUsage); // // Generate "annotation:StoreGeneratedPattern="Identity"" for model schema // if (_isModel && member.MetadataProperties.Contains(DesignXmlConstants.EdmAnnotationNamespace + ":" + DesignXmlConstants.StoreGeneratedPattern)) { _writer.WriteAttributeString( TranslateFacetNameToAttributeName( DesignXmlConstants.StoreGeneratedPattern), DesignXmlConstants.EdmAnnotationNamespace, GetAttributeValueString( member.MetadataProperties[DesignXmlConstants.EdmAnnotationNamespace + ":" + DesignXmlConstants.StoreGeneratedPattern].Value)); } _writer.WriteEndElement(); } private void WritePropertyTypeFacets(TypeUsage typeUsage) { // we need to use the facets for this particular provider, not the ones that they type // may have been converted to (think CSDL types converted to provider types) EdmType type = GetEdmType(typeUsage); IEnumerable providerDescriptions = GetAssociatedFacetDescriptions(type); foreach (Facet facet in typeUsage.Facets) { FacetDescription providerFacetDescription = null; if (IsSpecialFacet(facet)) { providerFacetDescription = facet.Description; } else { foreach (FacetDescription description in providerDescriptions) { if (description.FacetName == facet.Name) { providerFacetDescription = description; break; } } } // // Don't emit this facet if we shouldn't // if (SkipFacet(facet, providerFacetDescription)) { continue; } // // Special case for MaxLength facet value of "Max" // if (_isModel && type.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType) { PrimitiveType primitiveType = (PrimitiveType)type; if ((primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.String || primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Binary) && facet.Name == DbProviderManifest.MaxLengthFacetName && Helper.IsUnboundedFacetValue(facet)) { _writer.WriteAttributeString(TranslateFacetNameToAttributeName(facet.Name), XmlConstants.Max); continue; } } _writer.WriteAttributeString(TranslateFacetNameToAttributeName(facet.Name), GetAttributeValueString(facet.Value)); } } private string TranslateFacetNameToAttributeName(string facetName) { if(DbProviderManifest.DefaultValueFacetName == facetName) { return XmlConstants.DefaultValueAttribute; } return facetName; } /// /// Should this facet be skipped ? /// A facet should be skipped if it satsifies one of the following /// - the providerFacetDescription is null - (ie) the provider knows of no such facet /// - the facetDescription indicates that the facet must have a constant value /// - the facet value is null /// - the facet value is the default value for the facet, and the facet is not required /// - we're emitting a model schema, and the facet in question is one of the following /// - MaxLength, FixedLength, Unicode, Collation, Precision, Scale, DateTimeKind /// /// the facet in question /// facet description in the provider /// true, if the facet should be skipped private bool SkipFacet(Facet facet, FacetDescription providerFacetDescription) { // // if the provider doesn't recognize it, it will complain // when it sees it; so don't put it in // if (providerFacetDescription == null) { return true; } // skip it if it is constant for the current provider if (providerFacetDescription.IsConstant) { return true; } // // Null facets can and should be omitted // if (facet.Value == null) { return true; } // // skip if it is not required, and has the default value // if (!providerFacetDescription.IsRequired && facet.Value.Equals(providerFacetDescription.DefaultValue)) { return true; } return false; } private bool IsSpecialFacet(Facet facet) { if(_isModel) { return (facet.Name == "ClientAutoGenerated" || facet.Name == EdmProviderManifest.ConcurrencyModeFacetName || facet.Name == XmlConstants.StoreGeneratedPattern || facet.Name == DbProviderManifest.CollationFacetName); } else { return (facet.Name == EdmProviderManifest.StoreGeneratedPatternFacetName || facet.Name == DbProviderManifest.CollationFacetName); } } private IEnumerable GetAssociatedFacetDescriptions(EdmType type) { MethodInfo mi = typeof(EdmType).GetMethod("GetAssociatedFacetDescriptions", BindingFlags.NonPublic | BindingFlags.Instance); Debug.Assert(mi != null, "Method GetAssociatedFacetDescriptions is missing"); return (IEnumerable)mi.Invoke(type, new object[0]); } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")] private string GetAttributeValueString(object o) { if (o.GetType() == typeof(bool)) { return o.ToString().ToLower(CultureInfo.InvariantCulture); } else { return o.ToString(); } } private EdmType GetEdmType(TypeUsage typeUsage) { if (_isModel) { return GetModelType(typeUsage.EdmType); } else { return typeUsage.EdmType; } } private string GetTypeName(TypeUsage typeUsage) { EdmType type = GetEdmType(typeUsage); if (type.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType) { return type.Name; } else { return GetFullName(type); } } private EdmType GetModelType(EdmType edmType) { if (edmType.BuiltInTypeKind != BuiltInTypeKind.PrimitiveType) { return edmType; } while (edmType != null && edmType.NamespaceName != EdmNamespace) { edmType = edmType.BaseType; } return edmType; } private void WriteSchemaElement(string schemaNamespace, string provider, string providerManifestToken, params KeyValuePair[] xmlPrefixToNamespaces) { string xmlNamespace = EntityFrameworkVersions.GetSchemaNamespace(_schemaVersion, _isModel ? DataSpace.CSpace : DataSpace.SSpace); _writer.WriteStartElement(XmlConstants.Schema, xmlNamespace); _writer.WriteAttributeString(XmlConstants.Namespace, schemaNamespace); _writer.WriteAttributeString(XmlConstants.Alias, "Self"); if (_isModel && _schemaVersion >= EntityFrameworkVersions.Version3) { _writer.WriteAttributeString(XmlConstants.UseStrongSpatialTypes, XmlConstants.AnnotationNamespace, XmlConstants.False); } if (!_isModel) { if (!string.IsNullOrEmpty(provider)) { _writer.WriteAttributeString(XmlConstants.Provider, provider); } if (!string.IsNullOrEmpty(providerManifestToken)) { _writer.WriteAttributeString(XmlConstants.ProviderManifestToken, providerManifestToken); } } // write out the extra xml namespaces and their pretty prefix foreach (KeyValuePair xmlPrefixToNamespace in xmlPrefixToNamespaces) { // see http://www.w3.org/TR/2006/REC-xml-names-20060816/ _writer.WriteAttributeString("xmlns", xmlPrefixToNamespace.Key, null, xmlPrefixToNamespace.Value); } } private void WriteEntityContainerElement(EntityContainer container) { _writer.WriteStartElement(XmlConstants.EntityContainer); _writer.WriteAttributeString(XmlConstants.Name, container.Name); // // Generate "annotation:LazyLoadingEnabled="true"" for model schema // if (_isModel && container.MetadataProperties.Contains(DesignXmlConstants.EdmAnnotationNamespace + ":" + DesignXmlConstants.LazyLoadingEnabled)) { _writer.WriteAttributeString( TranslateFacetNameToAttributeName( DesignXmlConstants.LazyLoadingEnabled), DesignXmlConstants.EdmAnnotationNamespace, GetAttributeValueString( container.MetadataProperties[DesignXmlConstants.EdmAnnotationNamespace + ":" + DesignXmlConstants.LazyLoadingEnabled].Value)); } foreach (EntitySetBase set in container.BaseEntitySets) { switch (set.BuiltInTypeKind) { case BuiltInTypeKind.EntitySet: WriteEntitySetElement((EntitySet)set); break; case BuiltInTypeKind.AssociationSet: WriteAssociationSetElement((AssociationSet)set); break; default: throw EDesignUtil.NonSerializableType(set.BuiltInTypeKind); } } foreach (EdmFunction functionImport in container.FunctionImports.Where(fi => fi.IsComposableAttribute)) { WriteFunctionElement(functionImport); } _writer.WriteEndElement(); } private void WriteAssociationSetElement(AssociationSet associationSet) { _writer.WriteStartElement(XmlConstants.AssociationSet); _writer.WriteAttributeString(XmlConstants.Name, associationSet.Name); _writer.WriteAttributeString(XmlConstants.Association, GetFullName(associationSet.ElementType)); foreach (AssociationSetEnd end in associationSet.AssociationSetEnds) { WriteAssociationSetEndElement(end); } _writer.WriteEndElement(); } private void WriteAssociationSetEndElement(AssociationSetEnd end) { _writer.WriteStartElement(XmlConstants.End); _writer.WriteAttributeString(XmlConstants.Role, end.Name); _writer.WriteAttributeString(XmlConstants.EntitySet, end.EntitySet.Name); _writer.WriteEndElement(); } private void WriteEntitySetElement(EntitySet entitySet) { _writer.WriteStartElement(XmlConstants.EntitySet); _writer.WriteAttributeString(XmlConstants.Name, entitySet.Name); _writer.WriteAttributeString(XmlConstants.EntityType, GetFullName(entitySet.ElementType)); WriteExtendedPropertyAttributes(entitySet); MetadataProperty property; if (entitySet.MetadataProperties.TryGetValue(XmlConstants.DefiningQuery, false, out property) && property.Value != null) { _writer.WriteStartElement(XmlConstants.DefiningQuery); _writer.WriteString(entitySet.DefiningQuery); _writer.WriteEndElement(); } else { if (entitySet.MetadataProperties.TryGetValue(XmlConstants.Schema, false, out property) && property.Value != null) { _writer.WriteAttributeString(property.Name, property.Value.ToString()); } if (entitySet.MetadataProperties.TryGetValue(XmlConstants.Table, false, out property) && property.Value != null) { _writer.WriteAttributeString(property.Name, property.Value.ToString()); } } _writer.WriteEndElement(); } private void WriteExtendedPropertyAttributes(MetadataItem item) { foreach (MetadataProperty property in item.MetadataProperties.Where(p => p.PropertyKind == PropertyKind.Extended)) { string xmlNamespace, attributeName; if (MetadataUtil.TrySplitExtendedMetadataPropertyName(property.Name, out xmlNamespace, out attributeName)) { _writer.WriteAttributeString(attributeName, xmlNamespace, property.Value.ToString()); } } } private string GetFullName(EdmType type) { string namespaceName = null; string name; string modifierFormat = null; if (type.BuiltInTypeKind == BuiltInTypeKind.CollectionType) { type = ((CollectionType)type).TypeUsage.EdmType; modifierFormat = "Collection({0})"; } if (type.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType) { // primitive types are not required to be qualified name = type.Name; } else { namespaceName = type.NamespaceName; name = type.Name; } string qualifiedTypeName; if (namespaceName == null) { qualifiedTypeName = name; } else { qualifiedTypeName = namespaceName + "." + name; } if (modifierFormat != null) { qualifiedTypeName = string.Format(CultureInfo.InvariantCulture, modifierFormat, qualifiedTypeName); } return qualifiedTypeName; } } }