|
//---------------------------------------------------------------------
// <copyright file="MetadataItemSerializer.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
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
{
/// <summary>
/// This class is reponsible for serailizing Edm Metadata out to the appropriate file .csdl or .ssdl
/// </summary>
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<MetadataItem, List<EdmSchemaError>> { }
internal readonly string EdmNamespace = "Edm";
public static void WriteXml(XmlWriter writer, ItemCollection collection, string namespaceToWrite, Version schemaVersion, params KeyValuePair<string, string> [] xmlPrefixToNamespaces)
{
WriteXml(writer, collection, namespaceToWrite, new ErrorsLookup(), new List<EdmType>(), null, null, schemaVersion, xmlPrefixToNamespaces);
}
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)
{
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<EntityContainer>())
{
serializer.WriteEntityContainerElement(item);
}
foreach (EdmType type in collection.GetItems<EdmType>())
{
// 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<EdmMember>())
{
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<EdmProperty> 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<EdmProperty>())
{
WritePropertyElement(member);
}
foreach (NavigationProperty navigationProperty in entityType.NavigationProperties )
{
if (navigationProperty.DeclaringType == entityType)
{
WriteNavigationPropertyElement(navigationProperty);
}
}
_writer.WriteEndElement();
}
private void WriteErrorsComment(EdmType type)
{
List<EdmSchemaError> 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<FacetDescription> 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;
}
/// <summary>
/// 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
/// </summary>
/// <param name="facet">the facet in question</param>
/// <param name="providerFacetDescription">facet description in the provider</param>
/// <returns>true, if the facet should be skipped</returns>
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<FacetDescription> GetAssociatedFacetDescriptions(EdmType type)
{
MethodInfo mi = typeof(EdmType).GetMethod("GetAssociatedFacetDescriptions", BindingFlags.NonPublic | BindingFlags.Instance);
Debug.Assert(mi != null, "Method GetAssociatedFacetDescriptions is missing");
return (IEnumerable<FacetDescription>)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<string, string>[] 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<string, string> 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;
}
}
}
|