Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntityDesign / Design / System / Data / Entity / Design / EntityModelSchemaGenerator.cs / 2 / 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 IListErrors = 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 IListGenerateMetadata() { 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 Listmembers = 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 IListErrors = 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 IListGenerateMetadata() { 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 Listmembers = 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ToolBarOverflowPanel.cs
- DataKeyCollection.cs
- ObjectSet.cs
- Encoding.cs
- SchemaTypeEmitter.cs
- ObfuscationAttribute.cs
- ProfileSettings.cs
- ActivationServices.cs
- ControlTemplate.cs
- DocumentsTrace.cs
- QueryStringConverter.cs
- XmlDownloadManager.cs
- FixedSOMTableRow.cs
- RuleValidation.cs
- SolidBrush.cs
- ScrollProviderWrapper.cs
- DesignTimeVisibleAttribute.cs
- DataTemplateKey.cs
- WebServiceBindingAttribute.cs
- InternalEnumValidator.cs
- IsolatedStorage.cs
- XmlSchemaValidationException.cs
- DesignerDataSchemaClass.cs
- ObjectManager.cs
- ButtonBase.cs
- WebConvert.cs
- PageThemeBuildProvider.cs
- QueryCacheManager.cs
- TemplateControl.cs
- HttpResponseWrapper.cs
- DesignerHelpers.cs
- WebPartMinimizeVerb.cs
- PathParser.cs
- RolePrincipal.cs
- ColorTransform.cs
- LogoValidationException.cs
- WorkflowItemPresenter.cs
- SessionEndingEventArgs.cs
- MappingItemCollection.cs
- CompositionTarget.cs
- SchemaContext.cs
- XmlSchemaParticle.cs
- ToReply.cs
- SettingsPropertyIsReadOnlyException.cs
- Accessors.cs
- ShutDownListener.cs
- NullableFloatSumAggregationOperator.cs
- ColorConvertedBitmap.cs
- CompiledRegexRunner.cs
- CodeSubDirectory.cs
- MiniCustomAttributeInfo.cs
- HScrollProperties.cs
- PtsHelper.cs
- RegexWorker.cs
- NonClientArea.cs
- PublisherMembershipCondition.cs
- TextRangeEditLists.cs
- CorruptingExceptionCommon.cs
- OdbcEnvironmentHandle.cs
- WebColorConverter.cs
- ConfigurationLockCollection.cs
- Size.cs
- Pointer.cs
- DeferredReference.cs
- MainMenu.cs
- UIElement.cs
- CustomTypeDescriptor.cs
- LogStore.cs
- Currency.cs
- SiteMembershipCondition.cs
- BamlRecords.cs
- PowerStatus.cs
- ZipFileInfoCollection.cs
- DependencyPropertyKind.cs
- ListViewSortEventArgs.cs
- ExpressionStringBuilder.cs
- PropertyValueUIItem.cs
- MonitorWrapper.cs
- WorkflowMarkupSerializerMapping.cs
- PoisonMessageException.cs
- MessageDirection.cs
- ConvertTextFrag.cs
- QuaternionRotation3D.cs
- AppLevelCompilationSectionCache.cs
- XmlILConstructAnalyzer.cs
- MiniCustomAttributeInfo.cs
- Clock.cs
- AttachedPropertyDescriptor.cs
- SmiEventStream.cs
- SQLString.cs
- KeyManager.cs
- UnsafeNativeMethods.cs
- HwndSource.cs
- ObjectFullSpanRewriter.cs
- WeakReferenceKey.cs
- Effect.cs
- UniformGrid.cs
- ActivityStatusChangeEventArgs.cs
- XmlSiteMapProvider.cs
- RootBuilder.cs