1 //---------------------------------------------------------------------
2 // <copyright file="MetadataItemSerializer.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 using System.Data.Common;
11 using System.Collections.Generic;
13 using System.Data.Metadata.Edm;
14 using System.Reflection;
15 using System.Diagnostics;
17 using System.Globalization;
19 using System.Data.Entity.Design.SsdlGenerator;
22 namespace System.Data.Entity.Design.Common
25 /// This class is reponsible for serailizing Edm Metadata out to the appropriate file .csdl or .ssdl
27 internal class MetadataItemSerializer
29 public static readonly EdmType NoSpecificTypeSentinal = MetadataItem.GetBuiltInType(BuiltInTypeKind.EdmType);
31 private bool _isModel;
32 private ErrorsLookup _errorsLookup;
33 private XmlWriter _writer;
34 private Version _schemaVersion;
36 private MetadataItemSerializer(XmlWriter writer, bool isModel, ErrorsLookup errorsLookup, Version schemaVersion)
40 _errorsLookup = errorsLookup;
41 _schemaVersion = schemaVersion;
44 public class ErrorsLookup : Dictionary<MetadataItem, List<EdmSchemaError>> { }
46 internal readonly string EdmNamespace = "Edm";
48 public static void WriteXml(XmlWriter writer, ItemCollection collection, string namespaceToWrite, Version schemaVersion, params KeyValuePair<string, string> [] xmlPrefixToNamespaces)
50 WriteXml(writer, collection, namespaceToWrite, new ErrorsLookup(), new List<EdmType>(), null, null, schemaVersion, xmlPrefixToNamespaces);
53 internal static void WriteXml(XmlWriter writer, ItemCollection collection, string namespaceToWrite, ErrorsLookup errorsLookup, List<EdmType> commentedOutItems, string provider, string providerManifestToken, Version schemaVersion, params KeyValuePair<string, string>[] xmlPrefixToNamespaces)
55 Debug.Assert(writer != null, "writer parameter is null");
56 Debug.Assert(collection != null, "collection parameter is null");
57 Debug.Assert(errorsLookup != null, "errorsLookup parameter is null");
58 Debug.Assert(!string.IsNullOrEmpty(namespaceToWrite), "namespaceToWrite parameter is null or empty");
60 MetadataItemSerializer serializer = new MetadataItemSerializer(writer, collection.DataSpace == DataSpace.CSpace, errorsLookup, schemaVersion);
62 serializer.ValidateNamespace(namespaceToWrite);
63 serializer.WriteSchemaElement(namespaceToWrite, provider, providerManifestToken, xmlPrefixToNamespaces);
64 serializer.WriteErrorsComment(NoSpecificTypeSentinal);
65 foreach (EntityContainer item in collection.GetItems<EntityContainer>())
67 serializer.WriteEntityContainerElement(item);
70 foreach (EdmType type in collection.GetItems<EdmType>())
72 // is it in the right space (c or s)
73 // does it have the right namespace?
74 if (type.NamespaceName == namespaceToWrite)
76 serializer.WriteTypeElement(type);
80 if(commentedOutItems.Count > 0)
82 StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
83 XmlWriterSettings settings = new XmlWriterSettings();
84 settings.Indent = true;
85 settings.OmitXmlDeclaration = true;
86 // we can have more than one commented out type
87 // which will look like multiple root elements, so this is a fragment
88 settings.ConformanceLevel = ConformanceLevel.Fragment;
89 XmlWriter commentWriter = XmlWriter.Create(stringWriter, settings);
90 MetadataItemSerializer commmentSerializer = new MetadataItemSerializer(commentWriter, collection.DataSpace == DataSpace.CSpace, errorsLookup, schemaVersion);
91 foreach (EdmType type in commentedOutItems)
93 commmentSerializer.WriteTypeElement(type);
95 commentWriter.Flush();
96 //This is not the cleanest thing to do but XmlTextWriter
97 //does not allow writing xml comment characters while writing a comment.
98 //and since we know exactly the string we write, this is pretty safe.
99 string comment = RemoveXmlCommentCharacters(stringWriter);
100 writer.WriteComment(comment);
102 writer.WriteEndElement();
105 private static string RemoveXmlCommentCharacters(StringWriter stringWriter)
107 string comment = stringWriter.GetStringBuilder().ToString();
108 while (comment.Contains(XmlConstants.XmlCommentStartString))
110 comment = comment.Replace(XmlConstants.XmlCommentStartString, String.Empty);
112 while (comment.Contains(XmlConstants.XmlCommentEndString))
114 comment = comment.Replace(XmlConstants.XmlCommentEndString, String.Empty);
119 private void ValidateNamespace(string namespaceToWrite)
121 if (EdmItemCollection.IsSystemNamespace(MetadataItem.EdmProviderManifest, namespaceToWrite))
123 throw EDesignUtil.EdmReservedNamespace(namespaceToWrite);
127 private void WriteTypeElement(EdmType type)
129 WriteErrorsComment(type);
130 switch (type.BuiltInTypeKind)
132 case BuiltInTypeKind.EntityType:
133 WriteEntityTypeElement((EntityType)type);
135 case BuiltInTypeKind.AssociationType:
136 WriteAssociationTypeElement((AssociationType)type);
138 case BuiltInTypeKind.EdmFunction:
139 WriteFunctionElement((EdmFunction)type);
141 case BuiltInTypeKind.ComplexType:
142 WriteComplexTypeElement((ComplexType)type);
144 case BuiltInTypeKind.RowType:
145 WriteRowTypeElement((RowType)type);
148 throw EDesignUtil.NonSerializableType(type.BuiltInTypeKind);
152 private void WriteFunctionElement(EdmFunction function)
154 _writer.WriteStartElement(function.IsFunctionImport ? XmlConstants.FunctionImport : XmlConstants.Function);
155 _writer.WriteAttributeString(XmlConstants.Name, function.Name);
157 // Write function ReturnType as attribute if possible.
158 bool returnParameterHandled = false;
159 if (function.ReturnParameter != null)
161 var returnTypeUsage = function.ReturnParameter.TypeUsage;
162 bool collection = returnTypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType;
165 Debug.Assert(_schemaVersion >= EntityFrameworkVersions.Version3, "_schemaVersion >= EntityFrameworkVersions.Version3");
166 returnTypeUsage = ((CollectionType)returnTypeUsage.EdmType).TypeUsage;
168 if (TypeSemantics.IsPrimitiveType(returnTypeUsage) || TypeSemantics.IsNominalType(returnTypeUsage))
170 string typeName = GetFullName(returnTypeUsage.EdmType);
173 typeName = "Collection(" + typeName + ")";
175 _writer.WriteAttributeString(XmlConstants.ReturnType, typeName);
176 returnParameterHandled = true;
182 _writer.WriteAttributeString(XmlConstants.AggregateAttribute, GetAttributeValueString(function.AggregateAttribute));
183 _writer.WriteAttributeString(XmlConstants.BuiltInAttribute, GetAttributeValueString(function.BuiltInAttribute));
184 _writer.WriteAttributeString(XmlConstants.NiladicFunction, GetAttributeValueString(function.NiladicFunctionAttribute));
185 _writer.WriteAttributeString(XmlConstants.IsComposable, GetAttributeValueString(function.IsComposableAttribute));
186 _writer.WriteAttributeString(XmlConstants.ParameterTypeSemantics, GetAttributeValueString(function.ParameterTypeSemanticsAttribute));
188 else if (function.IsFunctionImport && function.IsComposableAttribute)
190 Debug.Assert(_schemaVersion >= EntityFrameworkVersions.Version3, "_schemaVersion >= EntityFrameworkVersions.Version3");
191 _writer.WriteAttributeString(XmlConstants.IsComposable, GetAttributeValueString(true));
194 if (function.StoreFunctionNameAttribute != null)
196 _writer.WriteAttributeString(XmlConstants.StoreFunctionName, function.StoreFunctionNameAttribute);
199 if(function.CommandTextAttribute != null)
201 Debug.Assert(!_isModel, "Serialization of CommandTextAttribute is not supported for CSDL.");
202 _writer.WriteAttributeString(XmlConstants.CommandText, function.CommandTextAttribute);
205 if (function.Schema != null)
207 _writer.WriteAttributeString(XmlConstants.Schema, function.Schema);
210 foreach (FunctionParameter parameter in function.Parameters)
212 WriteFunctionParameterElement(parameter);
215 // Write function ReturnType subelement if needed.
216 if (function.ReturnParameter != null && !returnParameterHandled)
218 // Handle a TVF in s-space: Collection(RowType)
219 if (function.ReturnParameter.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType)
221 Debug.Assert(_schemaVersion >= EntityFrameworkVersions.Version3 && !_isModel, "_schemaVersion >= EntityFrameworkVersions.Version3 && !_isModel");
222 var elementType = ((CollectionType)function.ReturnParameter.TypeUsage.EdmType).TypeUsage.EdmType;
223 Debug.Assert(elementType.BuiltInTypeKind == BuiltInTypeKind.RowType, "TVF return type is expected to be Collection(RowType)");
224 var rowType = (RowType)elementType;
225 _writer.WriteStartElement(XmlConstants.ReturnType);
226 _writer.WriteStartElement(XmlConstants.CollectionType);
227 WriteTypeElement(rowType);
228 _writer.WriteEndElement();
229 _writer.WriteEndElement();
230 returnParameterHandled = true;
234 Debug.Assert(function.ReturnParameter == null || returnParameterHandled, "ReturnParameter was not handled.");
235 _writer.WriteEndElement();
238 private void WriteFunctionParameterElement(FunctionParameter parameter)
240 _writer.WriteStartElement(XmlConstants.Parameter);
241 _writer.WriteAttributeString(XmlConstants.Name, parameter.Name);
242 _writer.WriteAttributeString(XmlConstants.TypeAttribute, GetFullName(parameter.TypeUsage.EdmType));
245 _writer.WriteAttributeString(XmlConstants.Mode, GetAttributeValueString(parameter.Mode));
247 _writer.WriteEndElement();
251 private void WriteComplexTypeElement(ComplexType complexType)
253 _writer.WriteStartElement(XmlConstants.ComplexType);
254 _writer.WriteAttributeString(XmlConstants.Name, complexType.Name);
255 if (complexType.BaseType != null)
257 _writer.WriteAttributeString(XmlConstants.BaseType, GetFullName(complexType.BaseType));
260 foreach (EdmMember member in complexType.GetDeclaredOnlyMembers<EdmMember>())
262 WritePropertyElement(member);
264 _writer.WriteEndElement();
267 private void WriteAssociationTypeElement(AssociationType associationType)
269 _writer.WriteStartElement(XmlConstants.Association);
270 _writer.WriteAttributeString(XmlConstants.Name, associationType.Name);
271 foreach (RelationshipEndMember end in associationType.RelationshipEndMembers)
273 WriteRelationshipEndElement(end);
276 foreach (ReferentialConstraint constraint in associationType.ReferentialConstraints)
278 WriteReferentialConstraintElement(constraint);
281 _writer.WriteEndElement();
284 private void WriteRowTypeElement(RowType rowType)
286 _writer.WriteStartElement(XmlConstants.RowType);
287 foreach (var property in rowType.Properties)
289 WritePropertyElement(property);
291 _writer.WriteEndElement();
294 private void WriteReferentialConstraintElement(ReferentialConstraint constraint)
296 _writer.WriteStartElement(XmlConstants.ReferentialConstraint);
297 WriteReferentialConstraintRoleElement(XmlConstants.PrincipalRole, constraint.FromRole, constraint.FromProperties);
298 WriteReferentialConstraintRoleElement(XmlConstants.DependentRole, constraint.ToRole, constraint.ToProperties);
299 _writer.WriteEndElement();
302 private void WriteReferentialConstraintRoleElement(string nodeName, RelationshipEndMember end, IList<EdmProperty> properties)
304 // Generate the principal and dependent role nodes
305 _writer.WriteStartElement(nodeName);
306 _writer.WriteAttributeString(XmlConstants.Role, end.Name);
307 for (int i = 0; i < properties.Count; i++)
309 _writer.WriteStartElement(XmlConstants.PropertyRef);
310 _writer.WriteAttributeString(XmlConstants.Name, properties[i].Name);
311 _writer.WriteEndElement();
313 _writer.WriteEndElement();
316 private void WriteRelationshipEndElement(RelationshipEndMember end)
318 _writer.WriteStartElement(XmlConstants.End);
319 _writer.WriteAttributeString(XmlConstants.Role, end.Name);
321 string typeName = GetFullName(((RefType)end.TypeUsage.EdmType).ElementType);
322 _writer.WriteAttributeString(XmlConstants.TypeAttribute, typeName);
323 _writer.WriteAttributeString(XmlConstants.Multiplicity, GetXmlMultiplicity(end.RelationshipMultiplicity));
324 if (end.DeleteBehavior != OperationAction.None)
326 WriteOperationActionElement(XmlConstants.OnDelete, end.DeleteBehavior);
328 _writer.WriteEndElement();
331 private void WriteOperationActionElement(string elementName, OperationAction operationAction)
333 _writer.WriteStartElement(elementName);
334 _writer.WriteAttributeString(XmlConstants.Action, operationAction.ToString());
335 _writer.WriteEndElement();
338 private string GetXmlMultiplicity(RelationshipMultiplicity relationshipMultiplicity)
340 switch(relationshipMultiplicity)
342 case RelationshipMultiplicity.Many:
344 case RelationshipMultiplicity.One:
346 case RelationshipMultiplicity.ZeroOrOne:
349 Debug.Fail("Did you add a new RelationshipMultiplicity?");
354 private void WriteEntityTypeElement(EntityType entityType)
356 _writer.WriteStartElement(XmlConstants.EntityType);
357 _writer.WriteAttributeString(XmlConstants.Name, entityType.Name);
358 if (entityType.BaseType != null)
360 _writer.WriteAttributeString(XmlConstants.BaseType, GetFullName(entityType.BaseType));
363 if (entityType.Abstract)
365 _writer.WriteAttributeString(XmlConstants.Abstract, XmlConstants.True);
368 if (entityType.KeyMembers.Count != 0 &&
369 entityType.KeyMembers[0].DeclaringType == entityType) // they are declared on this entity
371 _writer.WriteStartElement(XmlConstants.Key);
372 for (int i = 0; i < entityType.KeyMembers.Count; i++)
374 _writer.WriteStartElement(XmlConstants.PropertyRef);
375 _writer.WriteAttributeString(XmlConstants.Name, entityType.KeyMembers[i].Name);
376 _writer.WriteEndElement();
378 _writer.WriteEndElement();
381 foreach (EdmProperty member in entityType.GetDeclaredOnlyMembers<EdmProperty>())
383 WritePropertyElement(member);
386 foreach (NavigationProperty navigationProperty in entityType.NavigationProperties )
388 if (navigationProperty.DeclaringType == entityType)
390 WriteNavigationPropertyElement(navigationProperty);
393 _writer.WriteEndElement();
396 private void WriteErrorsComment(EdmType type)
398 List<EdmSchemaError> errors;
399 if (_errorsLookup.TryGetValue(type, out errors))
401 Debug.Assert(errors.Count > 0, "how did we get an empty errors collection?");
403 StringBuilder builder = new StringBuilder();
404 builder.AppendLine(Strings.MetadataItemErrorsFoundDuringGeneration);
405 foreach (EdmSchemaError error in errors)
407 builder.AppendLine(error.ToString());
409 _writer.WriteComment(builder.ToString());
413 private void WriteNavigationPropertyElement(NavigationProperty member)
415 _writer.WriteStartElement(XmlConstants.NavigationProperty);
416 _writer.WriteAttributeString(XmlConstants.Name, member.Name);
417 _writer.WriteAttributeString(XmlConstants.Relationship, member.RelationshipType.FullName);
418 _writer.WriteAttributeString(XmlConstants.FromRole, member.FromEndMember.Name);
419 _writer.WriteAttributeString(XmlConstants.ToRole, member.ToEndMember.Name);
420 _writer.WriteEndElement();
423 private void WritePropertyElement(EdmMember member)
425 _writer.WriteStartElement(XmlConstants.Property);
426 _writer.WriteAttributeString(XmlConstants.Name, member.Name);
427 _writer.WriteAttributeString(XmlConstants.TypeAttribute, GetTypeName(member.TypeUsage));
428 WritePropertyTypeFacets(member.TypeUsage);
431 // Generate "annotation:StoreGeneratedPattern="Identity"" for model schema
433 if (_isModel && member.MetadataProperties.Contains(DesignXmlConstants.EdmAnnotationNamespace + ":" + DesignXmlConstants.StoreGeneratedPattern))
435 _writer.WriteAttributeString(
436 TranslateFacetNameToAttributeName(
437 DesignXmlConstants.StoreGeneratedPattern),
438 DesignXmlConstants.EdmAnnotationNamespace,
439 GetAttributeValueString(
440 member.MetadataProperties[DesignXmlConstants.EdmAnnotationNamespace + ":" + DesignXmlConstants.StoreGeneratedPattern].Value));
443 _writer.WriteEndElement();
446 private void WritePropertyTypeFacets(TypeUsage typeUsage)
448 // we need to use the facets for this particular provider, not the ones that they type
449 // may have been converted to (think CSDL types converted to provider types)
450 EdmType type = GetEdmType(typeUsage);
451 IEnumerable<FacetDescription> providerDescriptions = GetAssociatedFacetDescriptions(type);
453 foreach (Facet facet in typeUsage.Facets)
455 FacetDescription providerFacetDescription = null;
456 if (IsSpecialFacet(facet))
458 providerFacetDescription = facet.Description;
462 foreach (FacetDescription description in providerDescriptions)
464 if (description.FacetName == facet.Name)
466 providerFacetDescription = description;
473 // Don't emit this facet if we shouldn't
475 if (SkipFacet(facet, providerFacetDescription))
481 // Special case for MaxLength facet value of "Max"
484 type.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType)
486 PrimitiveType primitiveType = (PrimitiveType)type;
488 if ((primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.String ||
489 primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Binary) &&
490 facet.Name == DbProviderManifest.MaxLengthFacetName &&
491 Helper.IsUnboundedFacetValue(facet))
493 _writer.WriteAttributeString(TranslateFacetNameToAttributeName(facet.Name), XmlConstants.Max);
498 _writer.WriteAttributeString(TranslateFacetNameToAttributeName(facet.Name), GetAttributeValueString(facet.Value));
503 private string TranslateFacetNameToAttributeName(string facetName)
505 if(DbProviderManifest.DefaultValueFacetName == facetName)
507 return XmlConstants.DefaultValueAttribute;
514 /// Should this facet be skipped ?
515 /// A facet should be skipped if it satsifies one of the following
516 /// - the providerFacetDescription is null - (ie) the provider knows of no such facet
517 /// - the facetDescription indicates that the facet must have a constant value
518 /// - the facet value is null
519 /// - the facet value is the default value for the facet, and the facet is not required
520 /// - we're emitting a model schema, and the facet in question is one of the following
521 /// - MaxLength, FixedLength, Unicode, Collation, Precision, Scale, DateTimeKind
523 /// <param name="facet">the facet in question</param>
524 /// <param name="providerFacetDescription">facet description in the provider</param>
525 /// <returns>true, if the facet should be skipped</returns>
526 private bool SkipFacet(Facet facet, FacetDescription providerFacetDescription)
529 // if the provider doesn't recognize it, it will complain
530 // when it sees it; so don't put it in
532 if (providerFacetDescription == null)
536 // skip it if it is constant for the current provider
537 if (providerFacetDescription.IsConstant)
543 // Null facets can and should be omitted
545 if (facet.Value == null)
551 // skip if it is not required, and has the default value
553 if (!providerFacetDescription.IsRequired &&
554 facet.Value.Equals(providerFacetDescription.DefaultValue))
562 private bool IsSpecialFacet(Facet facet)
566 return (facet.Name == "ClientAutoGenerated" ||
567 facet.Name == EdmProviderManifest.ConcurrencyModeFacetName ||
568 facet.Name == XmlConstants.StoreGeneratedPattern ||
569 facet.Name == DbProviderManifest.CollationFacetName);
573 return (facet.Name == EdmProviderManifest.StoreGeneratedPatternFacetName ||
574 facet.Name == DbProviderManifest.CollationFacetName);
578 private IEnumerable<FacetDescription> GetAssociatedFacetDescriptions(EdmType type)
580 MethodInfo mi = typeof(EdmType).GetMethod("GetAssociatedFacetDescriptions", BindingFlags.NonPublic | BindingFlags.Instance);
581 Debug.Assert(mi != null, "Method GetAssociatedFacetDescriptions is missing");
582 return (IEnumerable<FacetDescription>)mi.Invoke(type, new object[0]);
585 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
586 private string GetAttributeValueString(object o)
588 if (o.GetType() == typeof(bool))
590 return o.ToString().ToLower(CultureInfo.InvariantCulture);
598 private EdmType GetEdmType(TypeUsage typeUsage)
602 return GetModelType(typeUsage.EdmType);
606 return typeUsage.EdmType;
609 private string GetTypeName(TypeUsage typeUsage)
611 EdmType type = GetEdmType(typeUsage);
612 if (type.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType)
618 return GetFullName(type);
622 private EdmType GetModelType(EdmType edmType)
624 if (edmType.BuiltInTypeKind != BuiltInTypeKind.PrimitiveType)
629 while (edmType != null && edmType.NamespaceName != EdmNamespace)
631 edmType = edmType.BaseType;
637 private void WriteSchemaElement(string schemaNamespace, string provider, string providerManifestToken, params KeyValuePair<string, string>[] xmlPrefixToNamespaces)
639 string xmlNamespace = EntityFrameworkVersions.GetSchemaNamespace(_schemaVersion, _isModel ? DataSpace.CSpace : DataSpace.SSpace);
640 _writer.WriteStartElement(XmlConstants.Schema, xmlNamespace);
641 _writer.WriteAttributeString(XmlConstants.Namespace, schemaNamespace);
642 _writer.WriteAttributeString(XmlConstants.Alias, "Self");
643 if (_isModel && _schemaVersion >= EntityFrameworkVersions.Version3)
645 _writer.WriteAttributeString(XmlConstants.UseStrongSpatialTypes, XmlConstants.AnnotationNamespace, XmlConstants.False);
649 if (!string.IsNullOrEmpty(provider))
651 _writer.WriteAttributeString(XmlConstants.Provider, provider);
654 if (!string.IsNullOrEmpty(providerManifestToken))
656 _writer.WriteAttributeString(XmlConstants.ProviderManifestToken, providerManifestToken);
660 // write out the extra xml namespaces and their pretty prefix
661 foreach (KeyValuePair<string, string> xmlPrefixToNamespace in xmlPrefixToNamespaces)
663 // see http://www.w3.org/TR/2006/REC-xml-names-20060816/
664 _writer.WriteAttributeString("xmlns", xmlPrefixToNamespace.Key, null, xmlPrefixToNamespace.Value);
668 private void WriteEntityContainerElement(EntityContainer container)
670 _writer.WriteStartElement(XmlConstants.EntityContainer);
671 _writer.WriteAttributeString(XmlConstants.Name, container.Name);
674 // Generate "annotation:LazyLoadingEnabled="true"" for model schema
676 if (_isModel && container.MetadataProperties.Contains(DesignXmlConstants.EdmAnnotationNamespace + ":" + DesignXmlConstants.LazyLoadingEnabled))
678 _writer.WriteAttributeString(
679 TranslateFacetNameToAttributeName(
680 DesignXmlConstants.LazyLoadingEnabled),
681 DesignXmlConstants.EdmAnnotationNamespace,
682 GetAttributeValueString(
683 container.MetadataProperties[DesignXmlConstants.EdmAnnotationNamespace + ":" + DesignXmlConstants.LazyLoadingEnabled].Value));
686 foreach (EntitySetBase set in container.BaseEntitySets)
688 switch (set.BuiltInTypeKind)
690 case BuiltInTypeKind.EntitySet:
691 WriteEntitySetElement((EntitySet)set);
693 case BuiltInTypeKind.AssociationSet:
694 WriteAssociationSetElement((AssociationSet)set);
697 throw EDesignUtil.NonSerializableType(set.BuiltInTypeKind);
701 foreach (EdmFunction functionImport in container.FunctionImports.Where(fi => fi.IsComposableAttribute))
703 WriteFunctionElement(functionImport);
706 _writer.WriteEndElement();
709 private void WriteAssociationSetElement(AssociationSet associationSet)
711 _writer.WriteStartElement(XmlConstants.AssociationSet);
712 _writer.WriteAttributeString(XmlConstants.Name, associationSet.Name);
713 _writer.WriteAttributeString(XmlConstants.Association, GetFullName(associationSet.ElementType));
715 foreach (AssociationSetEnd end in associationSet.AssociationSetEnds)
717 WriteAssociationSetEndElement(end);
719 _writer.WriteEndElement();
722 private void WriteAssociationSetEndElement(AssociationSetEnd end)
724 _writer.WriteStartElement(XmlConstants.End);
725 _writer.WriteAttributeString(XmlConstants.Role, end.Name);
726 _writer.WriteAttributeString(XmlConstants.EntitySet, end.EntitySet.Name);
727 _writer.WriteEndElement();
730 private void WriteEntitySetElement(EntitySet entitySet)
732 _writer.WriteStartElement(XmlConstants.EntitySet);
733 _writer.WriteAttributeString(XmlConstants.Name, entitySet.Name);
734 _writer.WriteAttributeString(XmlConstants.EntityType, GetFullName(entitySet.ElementType));
735 WriteExtendedPropertyAttributes(entitySet);
737 MetadataProperty property;
738 if (entitySet.MetadataProperties.TryGetValue(XmlConstants.DefiningQuery, false, out property) &&
739 property.Value != null)
741 _writer.WriteStartElement(XmlConstants.DefiningQuery);
742 _writer.WriteString(entitySet.DefiningQuery);
743 _writer.WriteEndElement();
747 if (entitySet.MetadataProperties.TryGetValue(XmlConstants.Schema, false, out property) &&
748 property.Value != null)
750 _writer.WriteAttributeString(property.Name, property.Value.ToString());
753 if (entitySet.MetadataProperties.TryGetValue(XmlConstants.Table, false, out property) &&
754 property.Value != null)
756 _writer.WriteAttributeString(property.Name, property.Value.ToString());
761 _writer.WriteEndElement();
764 private void WriteExtendedPropertyAttributes(MetadataItem item)
766 foreach (MetadataProperty property in item.MetadataProperties.Where(p => p.PropertyKind == PropertyKind.Extended))
768 string xmlNamespace, attributeName;
769 if (MetadataUtil.TrySplitExtendedMetadataPropertyName(property.Name, out xmlNamespace, out attributeName))
771 _writer.WriteAttributeString(attributeName, xmlNamespace, property.Value.ToString());
776 private string GetFullName(EdmType type)
778 string namespaceName = null;
780 string modifierFormat = null;
782 if (type.BuiltInTypeKind == BuiltInTypeKind.CollectionType)
784 type = ((CollectionType)type).TypeUsage.EdmType;
785 modifierFormat = "Collection({0})";
788 if (type.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType)
790 // primitive types are not required to be qualified
795 namespaceName = type.NamespaceName;
799 string qualifiedTypeName;
800 if (namespaceName == null)
802 qualifiedTypeName = name;
806 qualifiedTypeName = namespaceName + "." + name;
809 if (modifierFormat != null)
811 qualifiedTypeName = string.Format(CultureInfo.InvariantCulture, modifierFormat, qualifiedTypeName);
814 return qualifiedTypeName;