EntityModelSchemaGenerator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntityDesign / Design / System / Data / Entity / Design / EntityModelSchemaGenerator.cs / 1 / EntityModelSchemaGenerator.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  	 [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System.Diagnostics; 
using System.Collections.Generic;
using System.Xml;
using System.Data.Metadata.Edm;
using System.Data.Entity.Design.Common; 
using System.Data.Entity.Design.SsdlGenerator;
using System.Reflection; 
using System.Data.Common.Utils; 

namespace System.Data.Entity.Design 
{
    /// 
    /// The class creates a default CCMapping between an EntityContainer in S space
    /// and an EntityContainer in C space. The Mapping will be created based on the 
    /// declared types of extents. So Inheritance does not work.
    ///  
    public sealed class EntityModelSchemaGenerator 
    {
        private const string ENTITY_CONTAINER_NAME_SUFFIX = "Context"; 
        private const string NAMESPACE_NAME_SUFFIX = "Model";
        private const string DEFAULT_NAMESPACE_NAME = "Application";

        #region Constructors 
        /// 
        /// Constructs an EntityModelGenerator 
        ///  
        /// The Store EntityContainer to create the Model Metadata from.
        /// The name to give the namespace. If null, the name of the storeEntityContainer will be used. 
        /// The name to give the Model EntityContainer. If null, a modified version of the namespace of the of a type referenced in storeEntityContainer will be used.
        public EntityModelSchemaGenerator(EntityContainer storeEntityContainer, string namespaceName, string modelEntityContainerName)
        {
            EDesignUtil.CheckArgumentNull(storeEntityContainer, "storeEntityContainer"); 
            EDesignUtil.CheckStringArgument(namespaceName, "namespaceName");
            EDesignUtil.CheckStringArgument(namespaceName, "modelEntityContainerName"); 
 
            string adjustedNamespaceName = CreateValildModelNamespaceName(namespaceName);
            if (adjustedNamespaceName != namespaceName) 
            {
                // the user gave us a bad namespace name
                throw EDesignUtil.InvalidNamespaceNameArgument(namespaceName);
            } 

            string adjustedEntityContanierName = CreateModelName(modelEntityContainerName); 
            if(adjustedEntityContanierName != modelEntityContainerName) 
            {
                throw EDesignUtil.InvalidEntityContainerNameArgument(modelEntityContainerName); 
            }

            Initialize(storeEntityContainer, namespaceName, modelEntityContainerName);
        } 

        private void Initialize(EntityContainer storeEntityContainer, string namespaceName, string modelEntityContainerName) 
        { 
            if (!MetadataUtil.IsStoreType(storeEntityContainer))
            { 
                throw EDesignUtil.InvalidStoreEntityContainer(storeEntityContainer.Name, "storeEntityContainer");
            }

            _storeEntityContainer = storeEntityContainer; 
            _namespaceName = namespaceName;
            _modelEntityContainerName = modelEntityContainerName; 
 
            SetupFields();
 
            if (modelEntityContainerName == storeEntityContainer.Name)
            {
                throw EDesignUtil.DuplicateEntityContainerName(_modelEntityContainerName, _storeEntityContainer.Name);
            } 
        }
        ///  
        /// Constructs an EntityModelGenerator 
        /// 
        ///  
        public EntityModelSchemaGenerator(EntityContainer storeEntityContainer)
        {
            Initialize(storeEntityContainer, null, null);
        } 
        #endregion
 
        #region Fields 
        private EntityContainer _storeEntityContainer;
        private EntityContainer _modelEntityContainer = null; 
        private OneToOneMappingSerializer.MappingLookups _mappingLookups = null;
        string _namespaceName = null;
        string _modelEntityContainerName = null;
        private EdmItemCollection _edmItemCollection; 
        #endregion
 
        #region Properties 
        /// 
        /// Gets the EntityContainer that was created 
        /// 
        public EntityContainer EntityContainer
        {
            get 
            {
                return _modelEntityContainer; 
            } 
        }
        ///  
        /// Gets the EntityContainer that was created
        /// 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
        public EdmItemCollection EdmItemCollection 
        {
            get 
            { 
                return _edmItemCollection;
            } 
        }
        #endregion

        // responsible for holding all the 
        // state for a single execution of the Load
        // method 
        private class LoadMethodSessionState 
        {
            public EdmItemCollection EdmItemCollection; 
            public IList Errors = new List();
            public UniqueIdentifierService UsedGlobalModelTypeNames = new UniqueIdentifierService(false);
            public UniqueIdentifierService UsedEntitySetBaseNames = new UniqueIdentifierService(false);
            public Dictionary FkProperties = new Dictionary(); 
            public Dictionary CandidateCollapsedAssociations = new Dictionary();
            public OneToOneMappingSerializer.MappingLookups MappingLookups = new OneToOneMappingSerializer.MappingLookups(); 
 
            internal void AddError(string message, ModelBuilderErrorCode errorCode, EdmSchemaErrorSeverity severity, Exception e)
            { 
                Debug.Assert(message != null, "message parameter is null");
                if (null == e)
                {
                    Errors.Add(new EdmSchemaError(message, (int)errorCode, severity)); 
                }
                else 
                { 
                    Errors.Add(new EdmSchemaError(message, (int)errorCode, severity, e));
                } 
            }
        }

        #region public methods 
        /// 
        /// This method reads the s-space metadata objects and creates 
        /// corosponding c-space metadata objects 
        /// 
        public IList GenerateMetadata() 
        {

            if (_modelEntityContainer != null)
            { 
                _modelEntityContainer = null;
                _mappingLookups = null; 
                _edmItemCollection = null; 
            }
 
            LoadMethodSessionState session = new LoadMethodSessionState();

            try
            { 
                session.EdmItemCollection = new EdmItemCollection();
 
                List storeAssociationSets = new List(); 
                CollectAllFkProperties(session);
 
                EntityContainer modelEntityContainer = new EntityContainer(_modelEntityContainerName, DataSpace.CSpace);

                // create the EntityTypes and EntitySets, and save up the AssociationSets for later.
                foreach (EntitySetBase storeSet in _storeEntityContainer.BaseEntitySets) 
                {
                    switch (storeSet.BuiltInTypeKind) 
                    { 
                        case BuiltInTypeKind.AssociationSet:
                            // save these, and create them after the EntityTypes and EntitySets have been created 
                            string errorMessage;
                            if (!EntityStoreSchemaGenerator.IsFkPartiallyContainedInPK(((AssociationSet)storeSet).ElementType, out errorMessage))
                            {
                                storeAssociationSets.Add((AssociationSet)storeSet); 
                            }
                            else 
                            { 
                                session.AddError(errorMessage, ModelBuilderErrorCode.UnsupportedForeinKeyPattern, EdmSchemaErrorSeverity.Error, null);
                            } 
                            break;
                        case BuiltInTypeKind.EntitySet:
                            EntitySet set = (EntitySet)storeSet;
                            session.CandidateCollapsedAssociations.Add(set, new OneToOneMappingSerializer.CollapsedEntityAssociationSet(set)); 
                            break;
                        default: 
                            // error 
                            throw EDesignUtil.MissingGenerationPatternForType(storeSet.BuiltInTypeKind);
                    } 
                }

                foreach (AssociationSet storeAssociationSet in storeAssociationSets)
                { 
                    SaveAssociationForCollapsedAssociationCandidate(session, storeAssociationSet);
                } 
 
                Set associationSetsFromCollapseCandidateRejects = new Set();
                IEnumerable invalidCandidates = FindAllInvalidCollapsedAssociationCandidates(session); 

                // now that we have gone through all of the association sets,
                foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in invalidCandidates)
                { 
                    session.CandidateCollapsedAssociations.Remove(collapsed.EntitySet);
 
                    // just create the entity set and save the association set to be added later 
                    EntitySet entitySet = CreateModelEntitySet(session, collapsed.EntitySet);
                    modelEntityContainer.AddEntitySetBase(entitySet); 
                    associationSetsFromCollapseCandidateRejects.AddRange(collapsed.AssociationSets);
                }

                // create all the associations for the invalid collapsed entity association candidates 
                foreach (AssociationSet storeAssociationSet in (IEnumerable)associationSetsFromCollapseCandidateRejects)
                { 
                    if (!IsAssociationPartOfCandidateCollapsedAssociation(session, storeAssociationSet)) 
                    {
                        AssociationSet set = CreateModelAssociationSet(session, storeAssociationSet); 
                        modelEntityContainer.AddEntitySetBase(set);
                    }
                }
 

                // save the set that needs to be created and mapped 
                session.MappingLookups.CollapsedEntityAssociationSets.AddRange(session.CandidateCollapsedAssociations.Values); 

                // do this in a seperate loop so we are sure all the necessary EntitySets have been created 
                foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in session.MappingLookups.CollapsedEntityAssociationSets)
                {
                    AssociationSet set = CreateModelAssociationSet(session, collapsed);
                    modelEntityContainer.AddEntitySetBase(set); 
                }
 
 

                if (!EntityStoreSchemaGenerator.HasErrorSeverityErrors(session.Errors)) 
                {

                    // add them to the collection so they will work if someone wants to use the collection
                    foreach (EntityType type in session.MappingLookups.StoreEntityTypeToModelEntityType.Values) 
                    {
                        type.SetReadOnly(); 
                        session.EdmItemCollection.AddInternal(type); 
                    }
 
                    foreach (AssociationType type in session.MappingLookups.StoreAssociationTypeToModelAssociationType.Values)
                    {
                        type.SetReadOnly();
                        session.EdmItemCollection.AddInternal(type); 
                    }
 
                    foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet set in session.MappingLookups.CollapsedEntityAssociationSets) 
                    {
                        set.ModelAssociationSet.ElementType.SetReadOnly(); 
                        session.EdmItemCollection.AddInternal(set.ModelAssociationSet.ElementType);
                    }
                    modelEntityContainer.SetReadOnly();
                    session.EdmItemCollection.AddInternal(modelEntityContainer); 

                    _modelEntityContainer = modelEntityContainer; 
                    _mappingLookups = session.MappingLookups; 
                    _edmItemCollection = session.EdmItemCollection;
                } 

            }
            catch (Exception e)
            { 
                if (EntityUtil.IsCatchableExceptionType(e))
                { 
                    // an exception in the code is definitely an error 
                    string message = EDesignUtil.GetMessagesFromEntireExceptionChain(e);
                    session.AddError(message, 
                    ModelBuilderErrorCode.UnknownError,
                    EdmSchemaErrorSeverity.Error,
                    e);
                } 
                else
                { 
                    throw; 
                }
 
            }
            return session.Errors;
        }
 
        private IEnumerable FindAllInvalidCollapsedAssociationCandidates(LoadMethodSessionState session)
        { 
            Set invalid = new Set(); 
            Dictionary newCandidates = new Dictionary();
            foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in session.CandidateCollapsedAssociations.Values) 
            {
                if (!collapsed.MeetsRequirementsForCollapsableAssociation)
                {
                    invalid.Add(collapsed); 
                }
                else 
                { 
                    newCandidates.Add(collapsed.EntitySet, collapsed);
                } 
            }


            foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in newCandidates.Values) 
            {
                foreach (AssociationSet set in collapsed.AssociationSets) 
                { 
                    EntitySet end0Set = set.AssociationSetEnds[0].EntitySet;
                    EntitySet end1Set = set.AssociationSetEnds[1].EntitySet; 

                    // if both ends of the association are candidates throw both candidates out
                    // because we can't collapse two entities out
                    // and we don't know which entity we should collapse 
                    // so we won't collapse either
                    if (newCandidates.ContainsKey(end0Set) && 
                        newCandidates.ContainsKey(end1Set)) 
                    {
                        OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed0 = session.CandidateCollapsedAssociations[end0Set]; 
                        OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed1 = session.CandidateCollapsedAssociations[end1Set];
                        invalid.Add(collapsed0);
                        invalid.Add(collapsed1);
                    } 

                } 
            } 

            return invalid; 
        }

        private bool IsAssociationPartOfCandidateCollapsedAssociation(LoadMethodSessionState session, AssociationSet storeAssociationSet)
        { 
            foreach (AssociationSetEnd end in storeAssociationSet.AssociationSetEnds)
            { 
                if (session.CandidateCollapsedAssociations.ContainsKey(end.EntitySet)) 
                {
                    return true; 
                }
            }

            return false; 
        }
 
        private void SaveAssociationForCollapsedAssociationCandidate(LoadMethodSessionState session, AssociationSet storeAssociationSet) 
        {
            foreach (AssociationSetEnd end in storeAssociationSet.AssociationSetEnds) 
            {
                OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed;
                if (session.CandidateCollapsedAssociations.TryGetValue(end.EntitySet, out collapsed))
                { 
                    collapsed.AssociationSets.Add(storeAssociationSet);
                } 
            } 
        }
 
        private void CollectAllFkProperties(LoadMethodSessionState session)
        {
            foreach (EntitySetBase storeSet in _storeEntityContainer.BaseEntitySets)
            { 
                if (storeSet.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)
                { 
                    ReferentialConstraint constraint = OneToOneMappingSerializer.GetReferentialConstraint(((AssociationSet)storeSet)); 
                    foreach (EdmProperty property in constraint.ToProperties)
                    { 
                        if (!session.FkProperties.ContainsKey(property))
                        {
                            session.FkProperties.Add(property, ((AssociationSet)storeSet).ElementType);
                        } 
                    }
                } 
            } 
        }
 
        /// 
        /// Writes the Schema to xml
        /// 
        /// The name of the file to write the xml to. 
        public void WriteModelSchema(string outputFileName)
        { 
            EDesignUtil.CheckStringArgument(outputFileName, "outputFileName"); 
            CheckValidSchema();
 
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            using (XmlWriter writer = XmlWriter.Create(outputFileName, settings))
            { 
                WriteModelSchema(writer);
            } 
        } 

        ///  
        /// Writes the Schema to xml.
        /// 
        /// The XmlWriter to write the xml to.
        public void WriteModelSchema(XmlWriter writer) 
        {
            EDesignUtil.CheckArgumentNull(writer, "writer"); 
            CheckValidSchema(); 

            MetadataItemSerializer.WriteXml(writer, _edmItemCollection, _namespaceName); 
        }

        /// 
        /// Writes the cs mapping Schema to xml 
        /// 
        /// The name of the file to write the xml to. 
        public void WriteStorageMapping(string outputFileName) 
        {
            EDesignUtil.CheckStringArgument(outputFileName, "outputFileName"); 
            CheckValidSchema();

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true; 
            using (XmlWriter writer = XmlWriter.Create(outputFileName, settings))
            { 
                WriteStorageMapping(writer); 
            }
        } 

        /// 
        /// Writes the Schema to xml.
        ///  
        /// The XmlWriter to write the xml to.
        public void WriteStorageMapping(XmlWriter writer) 
        { 
            EDesignUtil.CheckArgumentNull(writer, "writer");
            CheckValidSchema(); 

            OneToOneMappingSerializer.WriteXml(writer, _mappingLookups, _storeEntityContainer, _modelEntityContainer);
        }
 
        #endregion
 
 
        // Get ModelSchemaNamespace name
        private void SetupFields() 
        {
            if( _modelEntityContainerName != null && _namespaceName != null)
            {
                return; 
            }
 
            string targetSchemaNamespace = null; 

            //Try and get the target schema namespace from one of the types or functions defined in the schema 
            foreach(EntitySetBase type in _storeEntityContainer.BaseEntitySets)
            {
                targetSchemaNamespace = type.ElementType.NamespaceName;
                break; 
            }
 
 
            if (string.IsNullOrEmpty(targetSchemaNamespace))
            { 
                // the default
                targetSchemaNamespace = DEFAULT_NAMESPACE_NAME;
            }
 

            if(_namespaceName == null) 
            { 
                // if the schema namespace has 'Target' then replace it with '.Model
                int index = targetSchemaNamespace.IndexOf("Target", StringComparison.OrdinalIgnoreCase); 
                if (index > 0)
                {
                    _namespaceName = CreateValildModelNamespaceName(targetSchemaNamespace.Substring(0, index) + NAMESPACE_NAME_SUFFIX);
                } 
                else
                { 
                    // else just append .Model to the name 
                    _namespaceName = CreateValildModelNamespaceName(targetSchemaNamespace + NAMESPACE_NAME_SUFFIX);
                } 
            }


            if(_modelEntityContainerName == null) 
            {
                // get default container name 
                int dotIndex = targetSchemaNamespace.IndexOf('.'); 
                if (dotIndex > 0)
                { 
                    _modelEntityContainerName = CreateModelName(targetSchemaNamespace.Substring(0, dotIndex) + ENTITY_CONTAINER_NAME_SUFFIX);
                }
                else
                { 
                    _modelEntityContainerName = CreateModelName(targetSchemaNamespace + ENTITY_CONTAINER_NAME_SUFFIX);
                } 
 
                int targetIndex = _modelEntityContainerName.IndexOf("Target", StringComparison.OrdinalIgnoreCase);
                if (targetIndex > 0) 
                {
                    _modelEntityContainerName = CreateModelName(targetSchemaNamespace.Substring(0, targetIndex) + ENTITY_CONTAINER_NAME_SUFFIX);
                }
            } 
        }
 
        private void CheckValidSchema() 
        {
            if (_modelEntityContainer == null) 
            {
                throw EDesignUtil.EntityModelGeneratorSchemaNotLoaded();
            }
        } 

 
        private EntitySet CreateModelEntitySet(LoadMethodSessionState session, EntitySet storeEntitySet) 
        {
            EntityType entity = CreateModelEntity(session, storeEntitySet.ElementType); 

            string name = CreateModelName(storeEntitySet.Name, session.UsedEntitySetBaseNames);
            EntitySet set = new EntitySet(name, null, null, null, entity);
            session.MappingLookups.StoreEntitySetToModelEntitySet.Add(storeEntitySet, set); 
            return set;
        } 
 
        private EntityType CreateModelEntity(LoadMethodSessionState session, EntityType storeEntityType)
        { 
            Debug.Assert(MetadataUtil.IsStoreType(storeEntityType), "this is not a store type");
            Debug.Assert(storeEntityType.BaseType == null, "we are assuming simple generation from a database where no types will have a base type");

            EntityType foundEntity; 
            if (session.MappingLookups.StoreEntityTypeToModelEntityType.TryGetValue(storeEntityType, out foundEntity))
            { 
                // this entity type is used in two different entity sets 
                return foundEntity;
            } 

            // create all the properties
            List members = new List();
            List keyMemberNames = new List(); 
            UniqueIdentifierService usedPropertyNames = new UniqueIdentifierService(false);
 
            string name = CreateModelName(storeEntityType.Name, session.UsedGlobalModelTypeNames); 
            // Don't want to have a property with the same name as the entity
            usedPropertyNames.RegisterUsedIdentifier(name); 
            foreach (EdmProperty storeProperty in storeEntityType.Properties)
            {
                // only add non fk properties
                EdmMember member; 
                bool isKey = storeEntityType.KeyMembers.TryGetValue(storeProperty.Name, false, out member);
 
                AssociationType association; 
                bool isPartOfRelationship = session.FkProperties.TryGetValue(storeProperty, out association);
 
                if (!isPartOfRelationship || isKey)
                {
                    EdmProperty property = CreateModelProperty(session, _namespaceName + "." + name, storeProperty, usedPropertyNames);
                    members.Add(property); 
                    if (isKey)
                    { 
                        keyMemberNames.Add(property.Name); 
                    }
                } 
            }

            EntityType entity = new EntityType(name,
                        _namespaceName, 
                        DataSpace.CSpace,
                        keyMemberNames, 
                        members); 

            session.MappingLookups.StoreEntityTypeToModelEntityType.Add(storeEntityType, entity); 
            return entity;
        }

        private EdmProperty CreateModelProperty(LoadMethodSessionState session, string declaringTypeName, EdmProperty storeProperty, UniqueIdentifierService usedPropertyNames) 
        {
            string name = CreateModelName(storeProperty.Name, usedPropertyNames); 
            TypeUsage cspaceTypeUsage = storeProperty.TypeUsage.GetModelTypeUsage(); 
            EdmProperty property = new EdmProperty(name, cspaceTypeUsage);
            session.MappingLookups.StoreEdmPropertyToModelEdmProperty.Add(storeProperty, property); 
            return property;
        }

 
        private AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsedAssociationSet)
        { 
            // create the association 
            string associationName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedGlobalModelTypeNames);
            AssociationType association = new AssociationType(associationName, 
                _namespaceName, DataSpace.CSpace);

            // create the association set
            string associationSetName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedEntitySetBaseNames); 
            AssociationSet set = new AssociationSet(associationSetName, association);
 
            // create the association and association set end members 
            UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false);
            for(int i = 0; i < collapsedAssociationSet.AssociationSets.Count; i++) 
            {
                AssociationSetEnd storeEnd;
                RelationshipMultiplicity multiplicity;
                OperationAction deleteBehavior; 
                collapsedAssociationSet.GetStoreAssociationSetEnd(i, out storeEnd, out multiplicity, out deleteBehavior);
                AssociationEndMember end = CreateAssociationEndMember(session, storeEnd.CorrespondingAssociationEndMember, usedEndMemberNames, multiplicity, deleteBehavior); 
                association.AddMember(end); 

                EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet]; 
                AssociationSetEnd setEnd = new AssociationSetEnd(entitySet, set, end);
                set.AddAssociationSetEnd(setEnd);
                session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, setEnd);
            } 

            // don't need a referential constraint 
 
            CreateModelNavigationProperties(session, association);
 
            collapsedAssociationSet.ModelAssociationSet = set;

            return set;
        } 

        private AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, AssociationSet storeAssociationSet) 
        { 

            AssociationType association; 
            // we will get a value when the same association is used for multiple association sets
            if (! session.MappingLookups.StoreAssociationTypeToModelAssociationType.TryGetValue(storeAssociationSet.ElementType, out association))
            {
                association = CreateModelAssociation(session, storeAssociationSet.ElementType); 
                session.MappingLookups.StoreAssociationTypeToModelAssociationType.Add(storeAssociationSet.ElementType, association);
            } 
 
            string name = CreateModelName(storeAssociationSet.Name, session.UsedEntitySetBaseNames);
            AssociationSet set = new AssociationSet(name, association); 

            foreach(AssociationSetEnd storeEnd in storeAssociationSet.AssociationSetEnds)
            {
                AssociationSetEnd end = CreateModelAssociationSetEnd(session, storeEnd, set); 
                session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, end);
                set.AddAssociationSetEnd(end); 
            } 
            session.MappingLookups.StoreAssociationSetToModelAssociationSet.Add(storeAssociationSet, set);
            return set; 
        }

        private AssociationSetEnd CreateModelAssociationSetEnd(LoadMethodSessionState session, AssociationSetEnd storeEnd, AssociationSet parentModelAssociationSet)
        { 
            AssociationEndMember associationEnd = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[storeEnd.CorrespondingAssociationEndMember];
            EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet]; 
            string role = associationEnd.Name; 
            AssociationSetEnd end = new AssociationSetEnd(entitySet, parentModelAssociationSet, associationEnd);
            return end; 
        }

        private AssociationType CreateModelAssociation(LoadMethodSessionState session, AssociationType storeAssociationType)
        { 
            UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false);
            string name = CreateModelName(storeAssociationType.Name, session.UsedGlobalModelTypeNames); 
            AssociationType association = new AssociationType(name, 
                _namespaceName,
                DataSpace.CSpace); 
            foreach (AssociationEndMember storeEndMember in storeAssociationType.RelationshipEndMembers)
            {
                AssociationEndMember end = CreateAssociationEndMember(session, storeEndMember, usedEndMemberNames);
                session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember.Add(storeEndMember, end); 
                association.AddMember(end);
            } 
 
            ReferentialConstraint constraint = CreateReferentialConstraint(session, storeAssociationType);
            if (constraint != null) 
            {
                association.AddReferentialConstraint(constraint);
            }
 
            CreateModelNavigationProperties(session, association);
 
            return association; 
        }
 

        private ReferentialConstraint CreateReferentialConstraint(LoadMethodSessionState session, AssociationType storeAssociation)
        {
            Debug.Assert(session != null, "session parameter is null"); 
            Debug.Assert(storeAssociation != null, "storeAssociation parameter is null");
            Debug.Assert(storeAssociation.ReferentialConstraints.Count <= 1, "We don't have a reason to have more than one constraint yet"); 
 
            // does the store have any constraints
            if (storeAssociation.ReferentialConstraints.Count == 0) 
            {
                return null;
            }
 
            ReferentialConstraint storeConstraint = storeAssociation.ReferentialConstraints[0];
            Debug.Assert(storeConstraint.FromProperties.Count == storeConstraint.ToProperties.Count, "FromProperties and ToProperties have different counts"); 
            Debug.Assert(storeConstraint.FromProperties.Count != 0, "No properties in the constraint, why does the constraint exist?"); 
            Debug.Assert(storeConstraint.ToProperties[0].DeclaringType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "The property is not from an EntityType");
 
            EntityType toType = (EntityType)storeConstraint.ToProperties[0].DeclaringType;
            bool toPropertiesAreKey = toType.KeyMembers.Contains(storeConstraint.ToProperties[0]);
            // has an non primary key in the FK, this means all the FK are not PK
            // since we already checked the other condition which is the FK partially contains PK in the 
            // funciton IsFkPartiallyContainedInPK, so no referential constraints for this
            if (!toPropertiesAreKey) 
            { 
                return null;
            } 
            // we need a constraint so lets build it
            int count = storeConstraint.FromProperties.Count;
            EdmProperty[] fromProperties = new EdmProperty[count];
            EdmProperty[] toProperties = new EdmProperty[count]; 
            AssociationEndMember fromRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.FromRole];
            AssociationEndMember toRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.ToRole]; 
            for (int index = 0; index < count; index++) 
            {
                fromProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.FromProperties[index]]; 
                toProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.ToProperties[index]];
            }

            ReferentialConstraint newConstraint = new ReferentialConstraint( 
                fromRole,
                toRole, 
                fromProperties, 
                toProperties);
 
            return newConstraint;
        }

        private void CreateModelNavigationProperties(LoadMethodSessionState session, AssociationType association) 
        {
            Debug.Assert(association.Members.Count == 2, "this code assumes two ends"); 
            AssociationEndMember end1 = (AssociationEndMember)association.Members[0]; 
            AssociationEndMember end2 = (AssociationEndMember)association.Members[1];
 
            CreateModelNavigationProperty(session, end1, end2);
            CreateModelNavigationProperty(session, end2, end1);
        }
 
        private void CreateModelNavigationProperty(LoadMethodSessionState session, AssociationEndMember from, AssociationEndMember to)
        { 
            EntityType entityType = (EntityType)((RefType)from.TypeUsage.EdmType).ElementType; 
            UniqueIdentifierService usedMemberNames = new UniqueIdentifierService(false);
            LoadNameLookupWithUsedMemberNames(entityType, usedMemberNames); 
            string name = CreateModelName(to.Name, usedMemberNames);
            NavigationProperty navigationProperty = new NavigationProperty(name, to.TypeUsage);
            navigationProperty.RelationshipType = (AssociationType)to.DeclaringType;
            navigationProperty.ToEndMember = to; 
            navigationProperty.FromEndMember = from;
            entityType.AddMember(navigationProperty); 
        } 

        private void LoadNameLookupWithUsedMemberNames(EntityType entityType, UniqueIdentifierService usedMemberNames) 
        {
            // a property should not have the same name as its entity
            usedMemberNames.RegisterUsedIdentifier(entityType.Name);
            foreach (EdmMember member in entityType.Members) 
            {
                usedMemberNames.RegisterUsedIdentifier(member.Name); 
            } 
        }
 
        private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, UniqueIdentifierService usedEndMemberNames)
        {
            return CreateAssociationEndMember(session, storeEndMember, usedEndMemberNames, storeEndMember.RelationshipMultiplicity, storeEndMember.DeleteBehavior);
        } 

        private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, UniqueIdentifierService usedEndMemberNames, RelationshipMultiplicity multiplicityOverride, OperationAction deleteBehaviorOverride) 
        { 
            Debug.Assert(storeEndMember.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType, "The type is not a ref type");
            Debug.Assert(((RefType)storeEndMember.TypeUsage.EdmType).ElementType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "the ref is not holding on to an EntityType"); 

            EntityType storeEntityType = ((EntityType)((RefType)storeEndMember.TypeUsage.EdmType).ElementType);
            EntityType modelEntityType = session.MappingLookups.StoreEntityTypeToModelEntityType[storeEntityType];
 
            string name = CreateModelName(storeEndMember.Name, usedEndMemberNames);
            AssociationEndMember end = new AssociationEndMember(name, modelEntityType.GetReferenceType(), multiplicityOverride); 
            end.DeleteBehavior = deleteBehaviorOverride; 
            return end;
        } 

        private string CreateModelName(string storeName, UniqueIdentifierService usedNames)
        {
            string newName = CreateModelName(storeName); 
            newName = usedNames.AdjustIdentifier(newName);
            return newName; 
        } 

        private static string CreateValildModelNamespaceName(string storeNamespaceName) 
        {
            return CreateValidNamespaceName(storeNamespaceName, 'C');
        }
 
        internal static string CreateValidNamespaceName(string storeNamespaceName, char appendToFrontIfFirstCharIsInvalid)
        { 
            List namespaceParts = new List(); 
            foreach (string sPart in storeNamespaceName.Split(new char[] { '.' }))
            { 
                // each part of a namespace needs to be a valid
                // cspace name
                namespaceParts.Add(CreateValidEcmaName(sPart, appendToFrontIfFirstCharIsInvalid));
            } 

            string modelNamespaceName = ""; 
            for (int i = 0; i < namespaceParts.Count - 1; i++) 
            {
                modelNamespaceName += namespaceParts[i] + "."; 
            }
            modelNamespaceName += namespaceParts[namespaceParts.Count - 1];

 
            // We might get a clash in names if ssdl has two types named #table and $table. Both will generate C_table
            // We leave it to the calling method to resolve any name clashes 
            return modelNamespaceName; 
        }
 
        //This method maps invalid characters such as &^%,etc in order to generate valid names
        private static string CreateModelName(string storeName)
        {
            return CreateValidEcmaName(storeName, 'C'); 
        }
 
        internal static string CreateValidEcmaName(string name, char appendToFrontIfFirstCharIsInvalid) 
        {
            char[] ecmaNameArray = name.ToCharArray(); 
            for (int i = 0; i < ecmaNameArray.Length; i++)
            {
                // replace non -(letters or digits) with _ ( underscore )
                if (!char.IsLetterOrDigit(ecmaNameArray[i])) 
                {
                    ecmaNameArray[i] = '_'; 
                } 
            }
 
            string ecmaName = new string(ecmaNameArray);
            // the first letter in a part should only be a char
            if (!char.IsLetter(ecmaName[0]))
            { 
                ecmaName = appendToFrontIfFirstCharIsInvalid + ecmaName;
            } 
 
            return ecmaName;
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  	 [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System.Diagnostics; 
using System.Collections.Generic;
using System.Xml;
using System.Data.Metadata.Edm;
using System.Data.Entity.Design.Common; 
using System.Data.Entity.Design.SsdlGenerator;
using System.Reflection; 
using System.Data.Common.Utils; 

namespace System.Data.Entity.Design 
{
    /// 
    /// The class creates a default CCMapping between an EntityContainer in S space
    /// and an EntityContainer in C space. The Mapping will be created based on the 
    /// declared types of extents. So Inheritance does not work.
    ///  
    public sealed class EntityModelSchemaGenerator 
    {
        private const string ENTITY_CONTAINER_NAME_SUFFIX = "Context"; 
        private const string NAMESPACE_NAME_SUFFIX = "Model";
        private const string DEFAULT_NAMESPACE_NAME = "Application";

        #region Constructors 
        /// 
        /// Constructs an EntityModelGenerator 
        ///  
        /// The Store EntityContainer to create the Model Metadata from.
        /// The name to give the namespace. If null, the name of the storeEntityContainer will be used. 
        /// The name to give the Model EntityContainer. If null, a modified version of the namespace of the of a type referenced in storeEntityContainer will be used.
        public EntityModelSchemaGenerator(EntityContainer storeEntityContainer, string namespaceName, string modelEntityContainerName)
        {
            EDesignUtil.CheckArgumentNull(storeEntityContainer, "storeEntityContainer"); 
            EDesignUtil.CheckStringArgument(namespaceName, "namespaceName");
            EDesignUtil.CheckStringArgument(namespaceName, "modelEntityContainerName"); 
 
            string adjustedNamespaceName = CreateValildModelNamespaceName(namespaceName);
            if (adjustedNamespaceName != namespaceName) 
            {
                // the user gave us a bad namespace name
                throw EDesignUtil.InvalidNamespaceNameArgument(namespaceName);
            } 

            string adjustedEntityContanierName = CreateModelName(modelEntityContainerName); 
            if(adjustedEntityContanierName != modelEntityContainerName) 
            {
                throw EDesignUtil.InvalidEntityContainerNameArgument(modelEntityContainerName); 
            }

            Initialize(storeEntityContainer, namespaceName, modelEntityContainerName);
        } 

        private void Initialize(EntityContainer storeEntityContainer, string namespaceName, string modelEntityContainerName) 
        { 
            if (!MetadataUtil.IsStoreType(storeEntityContainer))
            { 
                throw EDesignUtil.InvalidStoreEntityContainer(storeEntityContainer.Name, "storeEntityContainer");
            }

            _storeEntityContainer = storeEntityContainer; 
            _namespaceName = namespaceName;
            _modelEntityContainerName = modelEntityContainerName; 
 
            SetupFields();
 
            if (modelEntityContainerName == storeEntityContainer.Name)
            {
                throw EDesignUtil.DuplicateEntityContainerName(_modelEntityContainerName, _storeEntityContainer.Name);
            } 
        }
        ///  
        /// Constructs an EntityModelGenerator 
        /// 
        ///  
        public EntityModelSchemaGenerator(EntityContainer storeEntityContainer)
        {
            Initialize(storeEntityContainer, null, null);
        } 
        #endregion
 
        #region Fields 
        private EntityContainer _storeEntityContainer;
        private EntityContainer _modelEntityContainer = null; 
        private OneToOneMappingSerializer.MappingLookups _mappingLookups = null;
        string _namespaceName = null;
        string _modelEntityContainerName = null;
        private EdmItemCollection _edmItemCollection; 
        #endregion
 
        #region Properties 
        /// 
        /// Gets the EntityContainer that was created 
        /// 
        public EntityContainer EntityContainer
        {
            get 
            {
                return _modelEntityContainer; 
            } 
        }
        ///  
        /// Gets the EntityContainer that was created
        /// 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
        public EdmItemCollection EdmItemCollection 
        {
            get 
            { 
                return _edmItemCollection;
            } 
        }
        #endregion

        // responsible for holding all the 
        // state for a single execution of the Load
        // method 
        private class LoadMethodSessionState 
        {
            public EdmItemCollection EdmItemCollection; 
            public IList Errors = new List();
            public UniqueIdentifierService UsedGlobalModelTypeNames = new UniqueIdentifierService(false);
            public UniqueIdentifierService UsedEntitySetBaseNames = new UniqueIdentifierService(false);
            public Dictionary FkProperties = new Dictionary(); 
            public Dictionary CandidateCollapsedAssociations = new Dictionary();
            public OneToOneMappingSerializer.MappingLookups MappingLookups = new OneToOneMappingSerializer.MappingLookups(); 
 
            internal void AddError(string message, ModelBuilderErrorCode errorCode, EdmSchemaErrorSeverity severity, Exception e)
            { 
                Debug.Assert(message != null, "message parameter is null");
                if (null == e)
                {
                    Errors.Add(new EdmSchemaError(message, (int)errorCode, severity)); 
                }
                else 
                { 
                    Errors.Add(new EdmSchemaError(message, (int)errorCode, severity, e));
                } 
            }
        }

        #region public methods 
        /// 
        /// This method reads the s-space metadata objects and creates 
        /// corosponding c-space metadata objects 
        /// 
        public IList GenerateMetadata() 
        {

            if (_modelEntityContainer != null)
            { 
                _modelEntityContainer = null;
                _mappingLookups = null; 
                _edmItemCollection = null; 
            }
 
            LoadMethodSessionState session = new LoadMethodSessionState();

            try
            { 
                session.EdmItemCollection = new EdmItemCollection();
 
                List storeAssociationSets = new List(); 
                CollectAllFkProperties(session);
 
                EntityContainer modelEntityContainer = new EntityContainer(_modelEntityContainerName, DataSpace.CSpace);

                // create the EntityTypes and EntitySets, and save up the AssociationSets for later.
                foreach (EntitySetBase storeSet in _storeEntityContainer.BaseEntitySets) 
                {
                    switch (storeSet.BuiltInTypeKind) 
                    { 
                        case BuiltInTypeKind.AssociationSet:
                            // save these, and create them after the EntityTypes and EntitySets have been created 
                            string errorMessage;
                            if (!EntityStoreSchemaGenerator.IsFkPartiallyContainedInPK(((AssociationSet)storeSet).ElementType, out errorMessage))
                            {
                                storeAssociationSets.Add((AssociationSet)storeSet); 
                            }
                            else 
                            { 
                                session.AddError(errorMessage, ModelBuilderErrorCode.UnsupportedForeinKeyPattern, EdmSchemaErrorSeverity.Error, null);
                            } 
                            break;
                        case BuiltInTypeKind.EntitySet:
                            EntitySet set = (EntitySet)storeSet;
                            session.CandidateCollapsedAssociations.Add(set, new OneToOneMappingSerializer.CollapsedEntityAssociationSet(set)); 
                            break;
                        default: 
                            // error 
                            throw EDesignUtil.MissingGenerationPatternForType(storeSet.BuiltInTypeKind);
                    } 
                }

                foreach (AssociationSet storeAssociationSet in storeAssociationSets)
                { 
                    SaveAssociationForCollapsedAssociationCandidate(session, storeAssociationSet);
                } 
 
                Set associationSetsFromCollapseCandidateRejects = new Set();
                IEnumerable invalidCandidates = FindAllInvalidCollapsedAssociationCandidates(session); 

                // now that we have gone through all of the association sets,
                foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in invalidCandidates)
                { 
                    session.CandidateCollapsedAssociations.Remove(collapsed.EntitySet);
 
                    // just create the entity set and save the association set to be added later 
                    EntitySet entitySet = CreateModelEntitySet(session, collapsed.EntitySet);
                    modelEntityContainer.AddEntitySetBase(entitySet); 
                    associationSetsFromCollapseCandidateRejects.AddRange(collapsed.AssociationSets);
                }

                // create all the associations for the invalid collapsed entity association candidates 
                foreach (AssociationSet storeAssociationSet in (IEnumerable)associationSetsFromCollapseCandidateRejects)
                { 
                    if (!IsAssociationPartOfCandidateCollapsedAssociation(session, storeAssociationSet)) 
                    {
                        AssociationSet set = CreateModelAssociationSet(session, storeAssociationSet); 
                        modelEntityContainer.AddEntitySetBase(set);
                    }
                }
 

                // save the set that needs to be created and mapped 
                session.MappingLookups.CollapsedEntityAssociationSets.AddRange(session.CandidateCollapsedAssociations.Values); 

                // do this in a seperate loop so we are sure all the necessary EntitySets have been created 
                foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in session.MappingLookups.CollapsedEntityAssociationSets)
                {
                    AssociationSet set = CreateModelAssociationSet(session, collapsed);
                    modelEntityContainer.AddEntitySetBase(set); 
                }
 
 

                if (!EntityStoreSchemaGenerator.HasErrorSeverityErrors(session.Errors)) 
                {

                    // add them to the collection so they will work if someone wants to use the collection
                    foreach (EntityType type in session.MappingLookups.StoreEntityTypeToModelEntityType.Values) 
                    {
                        type.SetReadOnly(); 
                        session.EdmItemCollection.AddInternal(type); 
                    }
 
                    foreach (AssociationType type in session.MappingLookups.StoreAssociationTypeToModelAssociationType.Values)
                    {
                        type.SetReadOnly();
                        session.EdmItemCollection.AddInternal(type); 
                    }
 
                    foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet set in session.MappingLookups.CollapsedEntityAssociationSets) 
                    {
                        set.ModelAssociationSet.ElementType.SetReadOnly(); 
                        session.EdmItemCollection.AddInternal(set.ModelAssociationSet.ElementType);
                    }
                    modelEntityContainer.SetReadOnly();
                    session.EdmItemCollection.AddInternal(modelEntityContainer); 

                    _modelEntityContainer = modelEntityContainer; 
                    _mappingLookups = session.MappingLookups; 
                    _edmItemCollection = session.EdmItemCollection;
                } 

            }
            catch (Exception e)
            { 
                if (EntityUtil.IsCatchableExceptionType(e))
                { 
                    // an exception in the code is definitely an error 
                    string message = EDesignUtil.GetMessagesFromEntireExceptionChain(e);
                    session.AddError(message, 
                    ModelBuilderErrorCode.UnknownError,
                    EdmSchemaErrorSeverity.Error,
                    e);
                } 
                else
                { 
                    throw; 
                }
 
            }
            return session.Errors;
        }
 
        private IEnumerable FindAllInvalidCollapsedAssociationCandidates(LoadMethodSessionState session)
        { 
            Set invalid = new Set(); 
            Dictionary newCandidates = new Dictionary();
            foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in session.CandidateCollapsedAssociations.Values) 
            {
                if (!collapsed.MeetsRequirementsForCollapsableAssociation)
                {
                    invalid.Add(collapsed); 
                }
                else 
                { 
                    newCandidates.Add(collapsed.EntitySet, collapsed);
                } 
            }


            foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in newCandidates.Values) 
            {
                foreach (AssociationSet set in collapsed.AssociationSets) 
                { 
                    EntitySet end0Set = set.AssociationSetEnds[0].EntitySet;
                    EntitySet end1Set = set.AssociationSetEnds[1].EntitySet; 

                    // if both ends of the association are candidates throw both candidates out
                    // because we can't collapse two entities out
                    // and we don't know which entity we should collapse 
                    // so we won't collapse either
                    if (newCandidates.ContainsKey(end0Set) && 
                        newCandidates.ContainsKey(end1Set)) 
                    {
                        OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed0 = session.CandidateCollapsedAssociations[end0Set]; 
                        OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed1 = session.CandidateCollapsedAssociations[end1Set];
                        invalid.Add(collapsed0);
                        invalid.Add(collapsed1);
                    } 

                } 
            } 

            return invalid; 
        }

        private bool IsAssociationPartOfCandidateCollapsedAssociation(LoadMethodSessionState session, AssociationSet storeAssociationSet)
        { 
            foreach (AssociationSetEnd end in storeAssociationSet.AssociationSetEnds)
            { 
                if (session.CandidateCollapsedAssociations.ContainsKey(end.EntitySet)) 
                {
                    return true; 
                }
            }

            return false; 
        }
 
        private void SaveAssociationForCollapsedAssociationCandidate(LoadMethodSessionState session, AssociationSet storeAssociationSet) 
        {
            foreach (AssociationSetEnd end in storeAssociationSet.AssociationSetEnds) 
            {
                OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed;
                if (session.CandidateCollapsedAssociations.TryGetValue(end.EntitySet, out collapsed))
                { 
                    collapsed.AssociationSets.Add(storeAssociationSet);
                } 
            } 
        }
 
        private void CollectAllFkProperties(LoadMethodSessionState session)
        {
            foreach (EntitySetBase storeSet in _storeEntityContainer.BaseEntitySets)
            { 
                if (storeSet.BuiltInTypeKind == BuiltInTypeKind.AssociationSet)
                { 
                    ReferentialConstraint constraint = OneToOneMappingSerializer.GetReferentialConstraint(((AssociationSet)storeSet)); 
                    foreach (EdmProperty property in constraint.ToProperties)
                    { 
                        if (!session.FkProperties.ContainsKey(property))
                        {
                            session.FkProperties.Add(property, ((AssociationSet)storeSet).ElementType);
                        } 
                    }
                } 
            } 
        }
 
        /// 
        /// Writes the Schema to xml
        /// 
        /// The name of the file to write the xml to. 
        public void WriteModelSchema(string outputFileName)
        { 
            EDesignUtil.CheckStringArgument(outputFileName, "outputFileName"); 
            CheckValidSchema();
 
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            using (XmlWriter writer = XmlWriter.Create(outputFileName, settings))
            { 
                WriteModelSchema(writer);
            } 
        } 

        ///  
        /// Writes the Schema to xml.
        /// 
        /// The XmlWriter to write the xml to.
        public void WriteModelSchema(XmlWriter writer) 
        {
            EDesignUtil.CheckArgumentNull(writer, "writer"); 
            CheckValidSchema(); 

            MetadataItemSerializer.WriteXml(writer, _edmItemCollection, _namespaceName); 
        }

        /// 
        /// Writes the cs mapping Schema to xml 
        /// 
        /// The name of the file to write the xml to. 
        public void WriteStorageMapping(string outputFileName) 
        {
            EDesignUtil.CheckStringArgument(outputFileName, "outputFileName"); 
            CheckValidSchema();

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true; 
            using (XmlWriter writer = XmlWriter.Create(outputFileName, settings))
            { 
                WriteStorageMapping(writer); 
            }
        } 

        /// 
        /// Writes the Schema to xml.
        ///  
        /// The XmlWriter to write the xml to.
        public void WriteStorageMapping(XmlWriter writer) 
        { 
            EDesignUtil.CheckArgumentNull(writer, "writer");
            CheckValidSchema(); 

            OneToOneMappingSerializer.WriteXml(writer, _mappingLookups, _storeEntityContainer, _modelEntityContainer);
        }
 
        #endregion
 
 
        // Get ModelSchemaNamespace name
        private void SetupFields() 
        {
            if( _modelEntityContainerName != null && _namespaceName != null)
            {
                return; 
            }
 
            string targetSchemaNamespace = null; 

            //Try and get the target schema namespace from one of the types or functions defined in the schema 
            foreach(EntitySetBase type in _storeEntityContainer.BaseEntitySets)
            {
                targetSchemaNamespace = type.ElementType.NamespaceName;
                break; 
            }
 
 
            if (string.IsNullOrEmpty(targetSchemaNamespace))
            { 
                // the default
                targetSchemaNamespace = DEFAULT_NAMESPACE_NAME;
            }
 

            if(_namespaceName == null) 
            { 
                // if the schema namespace has 'Target' then replace it with '.Model
                int index = targetSchemaNamespace.IndexOf("Target", StringComparison.OrdinalIgnoreCase); 
                if (index > 0)
                {
                    _namespaceName = CreateValildModelNamespaceName(targetSchemaNamespace.Substring(0, index) + NAMESPACE_NAME_SUFFIX);
                } 
                else
                { 
                    // else just append .Model to the name 
                    _namespaceName = CreateValildModelNamespaceName(targetSchemaNamespace + NAMESPACE_NAME_SUFFIX);
                } 
            }


            if(_modelEntityContainerName == null) 
            {
                // get default container name 
                int dotIndex = targetSchemaNamespace.IndexOf('.'); 
                if (dotIndex > 0)
                { 
                    _modelEntityContainerName = CreateModelName(targetSchemaNamespace.Substring(0, dotIndex) + ENTITY_CONTAINER_NAME_SUFFIX);
                }
                else
                { 
                    _modelEntityContainerName = CreateModelName(targetSchemaNamespace + ENTITY_CONTAINER_NAME_SUFFIX);
                } 
 
                int targetIndex = _modelEntityContainerName.IndexOf("Target", StringComparison.OrdinalIgnoreCase);
                if (targetIndex > 0) 
                {
                    _modelEntityContainerName = CreateModelName(targetSchemaNamespace.Substring(0, targetIndex) + ENTITY_CONTAINER_NAME_SUFFIX);
                }
            } 
        }
 
        private void CheckValidSchema() 
        {
            if (_modelEntityContainer == null) 
            {
                throw EDesignUtil.EntityModelGeneratorSchemaNotLoaded();
            }
        } 

 
        private EntitySet CreateModelEntitySet(LoadMethodSessionState session, EntitySet storeEntitySet) 
        {
            EntityType entity = CreateModelEntity(session, storeEntitySet.ElementType); 

            string name = CreateModelName(storeEntitySet.Name, session.UsedEntitySetBaseNames);
            EntitySet set = new EntitySet(name, null, null, null, entity);
            session.MappingLookups.StoreEntitySetToModelEntitySet.Add(storeEntitySet, set); 
            return set;
        } 
 
        private EntityType CreateModelEntity(LoadMethodSessionState session, EntityType storeEntityType)
        { 
            Debug.Assert(MetadataUtil.IsStoreType(storeEntityType), "this is not a store type");
            Debug.Assert(storeEntityType.BaseType == null, "we are assuming simple generation from a database where no types will have a base type");

            EntityType foundEntity; 
            if (session.MappingLookups.StoreEntityTypeToModelEntityType.TryGetValue(storeEntityType, out foundEntity))
            { 
                // this entity type is used in two different entity sets 
                return foundEntity;
            } 

            // create all the properties
            List members = new List();
            List keyMemberNames = new List(); 
            UniqueIdentifierService usedPropertyNames = new UniqueIdentifierService(false);
 
            string name = CreateModelName(storeEntityType.Name, session.UsedGlobalModelTypeNames); 
            // Don't want to have a property with the same name as the entity
            usedPropertyNames.RegisterUsedIdentifier(name); 
            foreach (EdmProperty storeProperty in storeEntityType.Properties)
            {
                // only add non fk properties
                EdmMember member; 
                bool isKey = storeEntityType.KeyMembers.TryGetValue(storeProperty.Name, false, out member);
 
                AssociationType association; 
                bool isPartOfRelationship = session.FkProperties.TryGetValue(storeProperty, out association);
 
                if (!isPartOfRelationship || isKey)
                {
                    EdmProperty property = CreateModelProperty(session, _namespaceName + "." + name, storeProperty, usedPropertyNames);
                    members.Add(property); 
                    if (isKey)
                    { 
                        keyMemberNames.Add(property.Name); 
                    }
                } 
            }

            EntityType entity = new EntityType(name,
                        _namespaceName, 
                        DataSpace.CSpace,
                        keyMemberNames, 
                        members); 

            session.MappingLookups.StoreEntityTypeToModelEntityType.Add(storeEntityType, entity); 
            return entity;
        }

        private EdmProperty CreateModelProperty(LoadMethodSessionState session, string declaringTypeName, EdmProperty storeProperty, UniqueIdentifierService usedPropertyNames) 
        {
            string name = CreateModelName(storeProperty.Name, usedPropertyNames); 
            TypeUsage cspaceTypeUsage = storeProperty.TypeUsage.GetModelTypeUsage(); 
            EdmProperty property = new EdmProperty(name, cspaceTypeUsage);
            session.MappingLookups.StoreEdmPropertyToModelEdmProperty.Add(storeProperty, property); 
            return property;
        }

 
        private AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsedAssociationSet)
        { 
            // create the association 
            string associationName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedGlobalModelTypeNames);
            AssociationType association = new AssociationType(associationName, 
                _namespaceName, DataSpace.CSpace);

            // create the association set
            string associationSetName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedEntitySetBaseNames); 
            AssociationSet set = new AssociationSet(associationSetName, association);
 
            // create the association and association set end members 
            UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false);
            for(int i = 0; i < collapsedAssociationSet.AssociationSets.Count; i++) 
            {
                AssociationSetEnd storeEnd;
                RelationshipMultiplicity multiplicity;
                OperationAction deleteBehavior; 
                collapsedAssociationSet.GetStoreAssociationSetEnd(i, out storeEnd, out multiplicity, out deleteBehavior);
                AssociationEndMember end = CreateAssociationEndMember(session, storeEnd.CorrespondingAssociationEndMember, usedEndMemberNames, multiplicity, deleteBehavior); 
                association.AddMember(end); 

                EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet]; 
                AssociationSetEnd setEnd = new AssociationSetEnd(entitySet, set, end);
                set.AddAssociationSetEnd(setEnd);
                session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, setEnd);
            } 

            // don't need a referential constraint 
 
            CreateModelNavigationProperties(session, association);
 
            collapsedAssociationSet.ModelAssociationSet = set;

            return set;
        } 

        private AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, AssociationSet storeAssociationSet) 
        { 

            AssociationType association; 
            // we will get a value when the same association is used for multiple association sets
            if (! session.MappingLookups.StoreAssociationTypeToModelAssociationType.TryGetValue(storeAssociationSet.ElementType, out association))
            {
                association = CreateModelAssociation(session, storeAssociationSet.ElementType); 
                session.MappingLookups.StoreAssociationTypeToModelAssociationType.Add(storeAssociationSet.ElementType, association);
            } 
 
            string name = CreateModelName(storeAssociationSet.Name, session.UsedEntitySetBaseNames);
            AssociationSet set = new AssociationSet(name, association); 

            foreach(AssociationSetEnd storeEnd in storeAssociationSet.AssociationSetEnds)
            {
                AssociationSetEnd end = CreateModelAssociationSetEnd(session, storeEnd, set); 
                session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, end);
                set.AddAssociationSetEnd(end); 
            } 
            session.MappingLookups.StoreAssociationSetToModelAssociationSet.Add(storeAssociationSet, set);
            return set; 
        }

        private AssociationSetEnd CreateModelAssociationSetEnd(LoadMethodSessionState session, AssociationSetEnd storeEnd, AssociationSet parentModelAssociationSet)
        { 
            AssociationEndMember associationEnd = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[storeEnd.CorrespondingAssociationEndMember];
            EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet]; 
            string role = associationEnd.Name; 
            AssociationSetEnd end = new AssociationSetEnd(entitySet, parentModelAssociationSet, associationEnd);
            return end; 
        }

        private AssociationType CreateModelAssociation(LoadMethodSessionState session, AssociationType storeAssociationType)
        { 
            UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false);
            string name = CreateModelName(storeAssociationType.Name, session.UsedGlobalModelTypeNames); 
            AssociationType association = new AssociationType(name, 
                _namespaceName,
                DataSpace.CSpace); 
            foreach (AssociationEndMember storeEndMember in storeAssociationType.RelationshipEndMembers)
            {
                AssociationEndMember end = CreateAssociationEndMember(session, storeEndMember, usedEndMemberNames);
                session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember.Add(storeEndMember, end); 
                association.AddMember(end);
            } 
 
            ReferentialConstraint constraint = CreateReferentialConstraint(session, storeAssociationType);
            if (constraint != null) 
            {
                association.AddReferentialConstraint(constraint);
            }
 
            CreateModelNavigationProperties(session, association);
 
            return association; 
        }
 

        private ReferentialConstraint CreateReferentialConstraint(LoadMethodSessionState session, AssociationType storeAssociation)
        {
            Debug.Assert(session != null, "session parameter is null"); 
            Debug.Assert(storeAssociation != null, "storeAssociation parameter is null");
            Debug.Assert(storeAssociation.ReferentialConstraints.Count <= 1, "We don't have a reason to have more than one constraint yet"); 
 
            // does the store have any constraints
            if (storeAssociation.ReferentialConstraints.Count == 0) 
            {
                return null;
            }
 
            ReferentialConstraint storeConstraint = storeAssociation.ReferentialConstraints[0];
            Debug.Assert(storeConstraint.FromProperties.Count == storeConstraint.ToProperties.Count, "FromProperties and ToProperties have different counts"); 
            Debug.Assert(storeConstraint.FromProperties.Count != 0, "No properties in the constraint, why does the constraint exist?"); 
            Debug.Assert(storeConstraint.ToProperties[0].DeclaringType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "The property is not from an EntityType");
 
            EntityType toType = (EntityType)storeConstraint.ToProperties[0].DeclaringType;
            bool toPropertiesAreKey = toType.KeyMembers.Contains(storeConstraint.ToProperties[0]);
            // has an non primary key in the FK, this means all the FK are not PK
            // since we already checked the other condition which is the FK partially contains PK in the 
            // funciton IsFkPartiallyContainedInPK, so no referential constraints for this
            if (!toPropertiesAreKey) 
            { 
                return null;
            } 
            // we need a constraint so lets build it
            int count = storeConstraint.FromProperties.Count;
            EdmProperty[] fromProperties = new EdmProperty[count];
            EdmProperty[] toProperties = new EdmProperty[count]; 
            AssociationEndMember fromRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.FromRole];
            AssociationEndMember toRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.ToRole]; 
            for (int index = 0; index < count; index++) 
            {
                fromProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.FromProperties[index]]; 
                toProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.ToProperties[index]];
            }

            ReferentialConstraint newConstraint = new ReferentialConstraint( 
                fromRole,
                toRole, 
                fromProperties, 
                toProperties);
 
            return newConstraint;
        }

        private void CreateModelNavigationProperties(LoadMethodSessionState session, AssociationType association) 
        {
            Debug.Assert(association.Members.Count == 2, "this code assumes two ends"); 
            AssociationEndMember end1 = (AssociationEndMember)association.Members[0]; 
            AssociationEndMember end2 = (AssociationEndMember)association.Members[1];
 
            CreateModelNavigationProperty(session, end1, end2);
            CreateModelNavigationProperty(session, end2, end1);
        }
 
        private void CreateModelNavigationProperty(LoadMethodSessionState session, AssociationEndMember from, AssociationEndMember to)
        { 
            EntityType entityType = (EntityType)((RefType)from.TypeUsage.EdmType).ElementType; 
            UniqueIdentifierService usedMemberNames = new UniqueIdentifierService(false);
            LoadNameLookupWithUsedMemberNames(entityType, usedMemberNames); 
            string name = CreateModelName(to.Name, usedMemberNames);
            NavigationProperty navigationProperty = new NavigationProperty(name, to.TypeUsage);
            navigationProperty.RelationshipType = (AssociationType)to.DeclaringType;
            navigationProperty.ToEndMember = to; 
            navigationProperty.FromEndMember = from;
            entityType.AddMember(navigationProperty); 
        } 

        private void LoadNameLookupWithUsedMemberNames(EntityType entityType, UniqueIdentifierService usedMemberNames) 
        {
            // a property should not have the same name as its entity
            usedMemberNames.RegisterUsedIdentifier(entityType.Name);
            foreach (EdmMember member in entityType.Members) 
            {
                usedMemberNames.RegisterUsedIdentifier(member.Name); 
            } 
        }
 
        private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, UniqueIdentifierService usedEndMemberNames)
        {
            return CreateAssociationEndMember(session, storeEndMember, usedEndMemberNames, storeEndMember.RelationshipMultiplicity, storeEndMember.DeleteBehavior);
        } 

        private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, UniqueIdentifierService usedEndMemberNames, RelationshipMultiplicity multiplicityOverride, OperationAction deleteBehaviorOverride) 
        { 
            Debug.Assert(storeEndMember.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType, "The type is not a ref type");
            Debug.Assert(((RefType)storeEndMember.TypeUsage.EdmType).ElementType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "the ref is not holding on to an EntityType"); 

            EntityType storeEntityType = ((EntityType)((RefType)storeEndMember.TypeUsage.EdmType).ElementType);
            EntityType modelEntityType = session.MappingLookups.StoreEntityTypeToModelEntityType[storeEntityType];
 
            string name = CreateModelName(storeEndMember.Name, usedEndMemberNames);
            AssociationEndMember end = new AssociationEndMember(name, modelEntityType.GetReferenceType(), multiplicityOverride); 
            end.DeleteBehavior = deleteBehaviorOverride; 
            return end;
        } 

        private string CreateModelName(string storeName, UniqueIdentifierService usedNames)
        {
            string newName = CreateModelName(storeName); 
            newName = usedNames.AdjustIdentifier(newName);
            return newName; 
        } 

        private static string CreateValildModelNamespaceName(string storeNamespaceName) 
        {
            return CreateValidNamespaceName(storeNamespaceName, 'C');
        }
 
        internal static string CreateValidNamespaceName(string storeNamespaceName, char appendToFrontIfFirstCharIsInvalid)
        { 
            List namespaceParts = new List(); 
            foreach (string sPart in storeNamespaceName.Split(new char[] { '.' }))
            { 
                // each part of a namespace needs to be a valid
                // cspace name
                namespaceParts.Add(CreateValidEcmaName(sPart, appendToFrontIfFirstCharIsInvalid));
            } 

            string modelNamespaceName = ""; 
            for (int i = 0; i < namespaceParts.Count - 1; i++) 
            {
                modelNamespaceName += namespaceParts[i] + "."; 
            }
            modelNamespaceName += namespaceParts[namespaceParts.Count - 1];

 
            // We might get a clash in names if ssdl has two types named #table and $table. Both will generate C_table
            // We leave it to the calling method to resolve any name clashes 
            return modelNamespaceName; 
        }
 
        //This method maps invalid characters such as &^%,etc in order to generate valid names
        private static string CreateModelName(string storeName)
        {
            return CreateValidEcmaName(storeName, 'C'); 
        }
 
        internal static string CreateValidEcmaName(string name, char appendToFrontIfFirstCharIsInvalid) 
        {
            char[] ecmaNameArray = name.ToCharArray(); 
            for (int i = 0; i < ecmaNameArray.Length; i++)
            {
                // replace non -(letters or digits) with _ ( underscore )
                if (!char.IsLetterOrDigit(ecmaNameArray[i])) 
                {
                    ecmaNameArray[i] = '_'; 
                } 
            }
 
            string ecmaName = new string(ecmaNameArray);
            // the first letter in a part should only be a char
            if (!char.IsLetter(ecmaName[0]))
            { 
                ecmaName = appendToFrontIfFirstCharIsInvalid + ecmaName;
            } 
 
            return ecmaName;
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK