private static void ValidateReferenceModeNamingChanged(ReferenceModeNamingCustomizesObjectType referenceModeNamingCustomizesObjectType) { if (null != referenceModeNamingCustomizesObjectType) { ORMCore.ObjectType objectType = referenceModeNamingCustomizesObjectType.ObjectType; if (objectType != null) { ConceptType conceptType = ConceptTypeIsForObjectType.GetConceptType(objectType); if (null == conceptType) { foreach (ORMCore.Role role in objectType.PlayedRoleCollection) { foreach (ConceptTypeChild conceptTypeChild in ConceptTypeChildHasPathFactType.GetConceptTypeChild(role.FactType)) { ValidateConceptTypeChildNameChanged(conceptTypeChild); } } } else { ValidateConceptTypeNameChanged(conceptType); } } } }
private static void UpdateChildNamesForFactTypeDelayedWorker(ModelElement element) { if (!element.IsDeleted) { FactType factType = (FactType)element; foreach (ConceptTypeChild child in ConceptTypeChildHasPathFactType.GetConceptTypeChild(factType)) { LinkedElementCollection <FactType> factTypePath = ConceptTypeChildHasPathFactType.GetPathFactTypeCollection(child); int pathCount; RoleBase towardsRole; RoleBase fromRole; if (0 != (pathCount = factTypePath.Count) && factType == factTypePath[pathCount - 1] && null != (towardsRole = FactTypeMapsTowardsRole.GetTowardsRole(factType)) && null != (fromRole = towardsRole.OppositeRole)) { string resolvedName = ResolveRoleName(fromRole); ConceptTypeReferencesConceptType reference; if (null != (reference = child as ConceptTypeReferencesConceptType)) { // Match original backwards pattern reference.OppositeName = resolvedName; child.Name = ResolveRoleName(towardsRole); } else { child.Name = resolvedName; } } } } }
private static void ValidateMandatoryDelayed(ModelElement element) { if (!element.IsDeleted) { ConceptTypeChild child = (ConceptTypeChild)element; bool newMandatory = true; foreach (FactType factType in ConceptTypeChildHasPathFactType.GetPathFactTypeCollection(child)) { FactTypeMapsTowardsRole towardsRoleLink = FactTypeMapsTowardsRole.GetLinkToTowardsRole(factType); if (null == towardsRoleLink) { newMandatory = false; break; } else { switch (towardsRoleLink.MandatoryPattern) { case MappingMandatoryPattern.None: case MappingMandatoryPattern.NotMandatory: case MappingMandatoryPattern.OppositeRoleMandatory: newMandatory = false; break; } if (!newMandatory) { break; } } } child.IsMandatory = newMandatory; } }
private static void FactTypeConstraintPatternChangedDelayed(ModelElement element) { FactType factType; ORMModel model; if (!element.IsDeleted && null != (model = (factType = (FactType)element).Model) && !ORMElementGateway.IsElementExcluded(factType)) { // If we're not previously mapped, then we will have been added at this point FactTypeMapsTowardsRole mapToRole = FactTypeMapsTowardsRole.GetLinkToTowardsRole(factType); if (mapToRole != null) { MappingMandatoryPattern startMandatoryPattern = mapToRole.MandatoryPattern; if (mapToRole.SynchronizeMappingPatterns()) { MappingMandatoryPattern endMandatoryPattern = mapToRole.MandatoryPattern; if (endMandatoryPattern != startMandatoryPattern) { foreach (ConceptTypeChild child in ConceptTypeChildHasPathFactType.GetConceptTypeChild(factType)) { ValidateMandatory(child, startMandatoryPattern, endMandatoryPattern); } } } else { AddTransactedModelElement(factType, ModelElementModification.ORMElementChanged); FrameworkDomainModel.DelayValidateElement(model, DelayValidateModel); } } } }
private static void UpdateNamesForObjectTypeDelayed(ModelElement element) { if (!element.IsDeleted) { ObjectType objectType = (ObjectType)element; string objectTypeName = objectType.Name; ConceptType conceptType = ConceptTypeIsForObjectType.GetConceptType(objectType); LinkedElementCollection <FactType> pathFactTypes; int factTypeCount; RoleBase towardsRole; RoleBase oppositeRole; if (null != conceptType) { // Precheck name to minimize downstream calls, the property change // will check itself. if (conceptType.Name != objectTypeName) { conceptType.Name = objectTypeName; foreach (ConceptTypeReferencesConceptType reference in ConceptTypeReferencesConceptType.GetLinksToReferencingConceptTypeCollection(conceptType)) { pathFactTypes = ConceptTypeChildHasPathFactType.GetPathFactTypeCollection(reference); if (0 != (factTypeCount = pathFactTypes.Count) && null != (towardsRole = FactTypeMapsTowardsRole.GetTowardsRole(pathFactTypes[factTypeCount - 1])) && null != (oppositeRole = towardsRole.OppositeRole)) { reference.OppositeName = ResolveRoleName(oppositeRole); } } foreach (ConceptTypeReferencesConceptType reference in ConceptTypeReferencesConceptType.GetLinksToReferencedConceptTypeCollection(conceptType)) { pathFactTypes = ConceptTypeChildHasPathFactType.GetPathFactTypeCollection(reference); if (0 != (factTypeCount = pathFactTypes.Count) && null != (towardsRole = FactTypeMapsTowardsRole.GetTowardsRole(pathFactTypes[factTypeCount - 1]))) { reference.Name = ResolveRoleName(towardsRole); } } } } InformationTypeFormat informationTypeFormat = InformationTypeFormatIsForValueType.GetInformationTypeFormat(objectType); if (null != informationTypeFormat) { if (informationTypeFormat.Name != objectTypeName) { informationTypeFormat.Name = objectTypeName; foreach (InformationType informationType in InformationType.GetLinksToConceptTypeCollection(informationTypeFormat)) { pathFactTypes = ConceptTypeChildHasPathFactType.GetPathFactTypeCollection(informationType); if (0 != (factTypeCount = pathFactTypes.Count) && null != (towardsRole = FactTypeMapsTowardsRole.GetTowardsRole(pathFactTypes[factTypeCount - 1])) && null != (oppositeRole = towardsRole.OppositeRole)) { informationType.Name = ResolveRoleName(oppositeRole); } } } } } }
/// <summary> /// Make sure we have our tracker attached to all loaded models. /// </summary> /// <param name="element">An ORMModel element</param> /// <param name="store">The context store</param> /// <param name="notifyAdded">The listener to notify if elements are added during fixup</param> protected sealed override void ProcessElement(ORMModel element, Store store, INotifyElementAdded notifyAdded) { AbstractionModel oil = AbstractionModelIsForORMModel.GetAbstractionModel(element); if (oil == null) { // UNDONE: DelayValidateModel currently deletes and recreates any existing // bridge relationship, so there is no point deleting it up front, we'll // just retrieve it later. Also note that DelayValidateModel does not call notifyAdded. DelayValidateModel(element); oil = AbstractionModelIsForORMModel.GetAbstractionModel(element); if (oil != null) { notifyAdded.ElementAdded(oil, true); } } else { AbstractionModelGenerationSetting generationSetting; bool regenerateForVersion = null == (generationSetting = GenerationSettingTargetsAbstractionModel.GetGenerationSetting(oil)) || generationSetting.AlgorithmVersion != CurrentAlgorithmVersion; bool excludedBridgedElement = false; ORMElementGateway.Initialize( element, regenerateForVersion ? (ORMElementGateway.NotifyORMElementExcluded) null : delegate(ORMModelElement modelElement) { if (excludedBridgedElement) { return; } ObjectType objectType; FactType factType; // Note that the types we're checking here are synchronized with the ORMElementGateway.ExclusionAdded method if (null != (objectType = modelElement as ObjectType)) { if (null != ConceptTypeIsForObjectType.GetLinkToConceptType(objectType) || null != InformationTypeFormatIsForValueType.GetLinkToInformationTypeFormat(objectType)) { excludedBridgedElement = true; } } else if (null != (factType = modelElement as FactType)) { if (null != FactTypeMapsTowardsRole.GetLinkToTowardsRole(factType) || ConceptTypeChildHasPathFactType.GetLinksToConceptTypeChild(factType).Count != 0) { excludedBridgedElement = true; } } }); if (regenerateForVersion || excludedBridgedElement) { // Something is very wrong, regenerate (does not regenerate the excluded elements we already have) DelayValidateModel(element); } } }
/// <summary> /// Implements <see cref="IVerbalize.GetVerbalization"/> /// </summary> protected bool GetVerbalization(TextWriter writer, IDictionary <Type, IVerbalizationSets> snippetsDictionary, IVerbalizationContext verbalizationContext, VerbalizationSign sign) { // We are redirected to this point by the associated Column element Column column = this.Column; bool firstWrite = true; foreach (ConceptTypeChild child in ColumnHasConceptTypeChild.GetConceptTypeChildPath(this.Column)) { foreach (FactType factType in ConceptTypeChildHasPathFactType.GetPathFactTypeCollection(child)) { if (firstWrite) { firstWrite = false; } else { writer.WriteLine(); } verbalizationContext.DeferVerbalization(factType, DeferVerbalizationOptions.MultipleVerbalizations, null); } } return(false); }
private static void FactTypeNamePartChanged(ORMCore.FactType factType) { bool checkPrimaryFactType = true; ORMCore.Objectification objectification = factType.Objectification; if (null != objectification) { foreach (ORMCore.FactType impliedFactType in objectification.ImpliedFactTypeCollection) { foreach (ConceptTypeChild child in ConceptTypeChildHasPathFactType.GetConceptTypeChild(impliedFactType)) { ValidateConceptTypeChildNameChanged(child); } } checkPrimaryFactType = factType.UnaryRole != null; } if (checkPrimaryFactType) { foreach (ConceptTypeChild child in ConceptTypeChildHasPathFactType.GetConceptTypeChild(factType)) { ValidateConceptTypeChildNameChanged(child); } } }
/// <summary> /// Get a minimal unique identifier for a column based on mapped roles. The identifer /// will stop as soon as the fact type is used in a single column or in a partitioned /// or separated column. /// </summary> /// <param name="column">The <see cref="Column"/> to analyze</param> /// <param name="idList">Scratch list used to determine keys</param> /// <param name="minKeySize">The minimum number of ids that uniquely /// identify this column. The actually key may be longer than this /// minimimum for partitioned and separated tables. Key comparisons /// may be performed down to this minimum size.</param> /// <returns><see langword="true"/> if the key was available.</returns> private static bool BuildKey(Column column, List <Guid> idList, out int minKeySize) { idList.Clear(); int uniqueUseIndex = -1; minKeySize = 0; LinkedElementCollection <ConceptTypeChild> childNodes = ColumnHasConceptTypeChild.GetConceptTypeChildPath(column); for (int i = childNodes.Count - 1; i >= 0; --i) { ConceptTypeChild child = childNodes[i]; bool uniqueChild = ColumnHasConceptTypeChild.GetLinksToColumn(child).Count == 1; LinkedElementCollection <FactType> pathFactTypes = ConceptTypeChildHasPathFactType.GetPathFactTypeCollection(child); int factTypeCount = pathFactTypes.Count; InformationType infoType; ObjectType objectType; if (0 != (factTypeCount = pathFactTypes.Count)) { for (int j = factTypeCount - 1; j >= 0; --j) { FactType factType = pathFactTypes[j]; idList.Add(FactTypeMapsTowardsRole.GetTowardsRole(factType).Id); if (-1 == uniqueUseIndex && uniqueChild && ConceptTypeChildHasPathFactType.GetLinksToConceptTypeChild(factType).Count == 1) { minKeySize = idList.Count; uniqueUseIndex = minKeySize - 1; } } ConceptTypeAssimilatesConceptType assimilation; if (uniqueUseIndex != -1 && null != (assimilation = child as ConceptTypeAssimilatesConceptType) && AssimilationMapping.GetAbsorptionChoiceFromAssimilation(assimilation) != AssimilationAbsorptionChoice.Absorb) { uniqueUseIndex = idList.Count - 1; } } else if (null != (infoType = child as InformationType) && null != (objectType = ConceptTypeIsForObjectType.GetObjectType(infoType.ConceptType))) { // Happens for a value column in an object type table, which has one concept type child idList.Add(objectType.Id); } } int count = idList.Count; if (0 == count) { return(false); } if (uniqueUseIndex != -1 && (uniqueUseIndex + 1) < count) { idList.RemoveRange(uniqueUseIndex + 1, count - uniqueUseIndex - 1); } if (minKeySize == 0) { minKeySize = idList.Count; } return(true); }
/// <summary> /// Generates the appropriate <see cref="ConceptTypeChild">concept type children</see> in <paramref name="parentConceptType"/> /// for <paramref name="factTypeMapping"/>. /// </summary> /// <param name="factTypeMappings"> /// The set of all decided <see cref="FactTypeMapping">fact type mappings</see>. /// </param> /// <param name="parentConceptType"> /// The <see cref="ConceptType"/> into which <see cref="ConceptTypeChild">concept type children</see> should be generated. /// </param> /// <param name="parentConceptTypeHasDeepAway"> /// Test if the parent concept type has a deep mapping away from it. Handles some cyclic cases by making a potential assimilation /// into a reference. Delay calculated because this is not always needed. /// </param> /// <param name="factTypeMapping"> /// The <see cref="FactTypeMapping"/> for which <see cref="ConceptTypeChild">concept type children</see> should be generated. /// </param> /// <param name="factTypePath"> /// The path of <see cref="FactType">fact types</see> leading from <paramref name="parentConceptType"/> to <paramref name="factTypeMapping"/> /// </param> /// <param name="isMandatorySoFar"> /// Indicates whether every step in <paramref name="factTypePath"/> is mandatory for the parent concept type (towards object type). /// </param> private static void GenerateConceptTypeChildrenForFactTypeMapping(FactTypeMappingDictionary factTypeMappings, ConceptType parentConceptType, ref bool? parentConceptTypeHasDeepAway, FactTypeMapping factTypeMapping, List<FactType> factTypePath, bool isMandatorySoFar) { // Push the current fact type onto the path. factTypePath.Add(factTypeMapping.FactType); bool isMandatory = isMandatorySoFar && (factTypeMapping.TowardsRoleMandatory); ConceptTypeChild newConceptTypeChild; ConceptType fromConceptType = ConceptTypeIsForObjectType.GetConceptType(factTypeMapping.FromObjectType); if (fromConceptType != null) { // The mapping is coming from a concept type, so we will create a concept type reference to it. // Set up the property assignments that are common to both kinds of concept type references. PropertyAssignment isMandatoryPropertyAssignment = new PropertyAssignment(ConceptTypeChild.IsMandatoryDomainPropertyId, isMandatory); string name = ResolveRoleName(factTypeMapping.FromRole); string oppositeName = ResolveRoleName(factTypeMapping.TowardsRole); // UNDONE: Yes, these are backwards, but they need to remain so for compatibility reasons until we do a file format change. PropertyAssignment namePropertyAssignment = new PropertyAssignment(ConceptTypeChild.NameDomainPropertyId, oppositeName); PropertyAssignment oppositeNamePropertyAssignment = new PropertyAssignment(ConceptTypeReferencesConceptType.OppositeNameDomainPropertyId, name); if (factTypeMapping.MappingDepth == MappingDepth.Deep) { // Since this is a deep mapping, we will create a concept type assimilation for it. SubtypeFact subtypeFact = factTypeMapping.FactType as SubtypeFact; // UNDONE: The handling here for IsPreferredForParent and IsPreferredForTarget may not be correct // if we have more than one fact type in the fact type path. bool isPreferredForTarget; if (subtypeFact != null) { // For subtype assimilations, IsPreferredForTarget matches the ProvidesPreferredIdentifier // property of the ORM subtype fact. isPreferredForTarget = subtypeFact.ProvidesPreferredIdentifier; } else { // For non-subtype assimilations, IsPreferredForTarget is true if the role played by the object // type corresponding to the parent concept type has the preferred identifying uniqueness constraint // for the target concept type. isPreferredForTarget = factTypeMapping.TowardsRole.SingleRoleAlethicUniquenessConstraint.IsPreferred; } bool isPreferredForParent = factTypeMapping.IsFromPreferredIdentifier; // The IsPreferredForParent property on concept type assimilations indicates that the assimilation, on its own, // provides the preferred identifier for the assimilating concept type. Although the IsFromPreferredIdentifier // property on the fact type mapping will be true even if the from role is part of a multi-role preferred identifier, // ORM currently doesn't allow a role with a single role alethic uniqueness constraint (which is required for this to // be a deep mapping) to be part of any other uniqueness constraint. However, this may change in the future as our // handling of derivations, implications, equivalences, and logical rules becomes more sophisticated. We assert here // in order to make this case easier to catch if it happens, since this method may need to be adjusted in that case // to ensure that it continues to produce correct results. Debug.Assert(!isPreferredForParent || factTypeMapping.FromRole.SingleRoleAlethicUniquenessConstraint.IsPreferred); newConceptTypeChild = new ConceptTypeAssimilatesConceptType(parentConceptType.Partition, new RoleAssignment[] { new RoleAssignment(ConceptTypeAssimilatesConceptType.AssimilatorConceptTypeDomainRoleId, parentConceptType), new RoleAssignment(ConceptTypeAssimilatesConceptType.AssimilatedConceptTypeDomainRoleId, fromConceptType) }, new PropertyAssignment[] { isMandatoryPropertyAssignment, namePropertyAssignment, oppositeNamePropertyAssignment, new PropertyAssignment(ConceptTypeAssimilatesConceptType.RefersToSubtypeDomainPropertyId, subtypeFact != null), new PropertyAssignment(ConceptTypeAssimilatesConceptType.IsPreferredForParentDomainPropertyId, isPreferredForParent), new PropertyAssignment(ConceptTypeAssimilatesConceptType.IsPreferredForTargetDomainPropertyId, isPreferredForTarget), }); } else { Debug.Assert(factTypeMapping.MappingDepth == MappingDepth.Shallow, "Collapse mappings should not come from object types that have a concept type."); // Since this is a shallow mapping, we will create a concept type relation for it. newConceptTypeChild = new ConceptTypeRelatesToConceptType(parentConceptType.Partition, new RoleAssignment[] { new RoleAssignment(ConceptTypeRelatesToConceptType.RelatingConceptTypeDomainRoleId, parentConceptType), new RoleAssignment(ConceptTypeRelatesToConceptType.RelatedConceptTypeDomainRoleId, fromConceptType) }, new PropertyAssignment[] { isMandatoryPropertyAssignment, namePropertyAssignment, oppositeNamePropertyAssignment }); } } else { // The mapping is not coming from a concept type, meaning that we either need an information // type for an atomic value type (which will already have an information type format created // for it), or we need to collapse the preferred identifier of an entity type or structured // value type. InformationTypeFormat fromInformationTypeFormat = InformationTypeFormatIsForValueType.GetInformationTypeFormat(factTypeMapping.FromObjectType); if (fromInformationTypeFormat != null) { // We have an information type format, which means that we need to create an information type. string name = ResolveRoleName(factTypeMapping.FromRole); newConceptTypeChild = new InformationType(parentConceptType.Partition, new RoleAssignment[] { new RoleAssignment(InformationType.ConceptTypeDomainRoleId, parentConceptType), new RoleAssignment(InformationType.InformationTypeFormatDomainRoleId, fromInformationTypeFormat) }, new PropertyAssignment[] { new PropertyAssignment(ConceptTypeChild.IsMandatoryDomainPropertyId, isMandatory), new PropertyAssignment(ConceptTypeChild.NameDomainPropertyId, name) }); } else { // We do not have an information type format, which means that we need to collapse the fact // types in the preferred identifier of the FromObjectType into the parent concept type. newConceptTypeChild = null; UniquenessConstraint preferredIdentifier = factTypeMapping.FromObjectType.PreferredIdentifier; Debug.Assert(preferredIdentifier != null); foreach (Role preferredIdentifierRole in preferredIdentifier.RoleCollection) { // NOTE: We don't need the ShouldIgnoreFactType filter here, because we would have ignored // this object type if we were ignoring any of the fact types in its preferred identifier. FactType preferredIdentifierFactType = preferredIdentifierRole.BinarizedFactType; FactTypeMapping preferredIdentifierFactTypeMapping = factTypeMappings[preferredIdentifierFactType]; if (preferredIdentifierFactType == factTypeMapping.FactType) { // We just got back to the fact that we were already mapping. This should only happen // when the object type has a single fact type in its preferred identifier and it is // deeply mapped away from the object type. Debug.Assert(preferredIdentifier.RoleCollection.Count == 1 && preferredIdentifierFactTypeMapping.MappingDepth == MappingDepth.Deep); // UNDONE: For now, we just ignore this fact type entirely. What we should be doing is: // 1) If everything along the path is mandatory, then we're done, since we know that instances of the parent // concept type always identify an instance of the object type that we're trying to map. // 2) Otherwise, check if there are any other relationships that would allow use to derive whether an instance // of the parent concept type identifies an instance of the object type that we're trying to map. Examples // of things that would allow us to do this would be a mandatory role played by the object type that we're // we're trying to map that gets absorbed into some concept type. The reference to an instance of this concept // type from it allows us to tell if this instance identifies an instance of the object type. // 3) If no other relationship allows us to derive this information, we need to add a boolean information type // that indicates for each instance of the parent concept type whether it identifies an instance of the object // type that we're trying to map. break; } // If we have a single fact type in the preferred identifier, it might be mapped // deeply away from the object type that we are collapsing. For this case, we need // to create a "fake" mapping and process it instead. if (preferredIdentifierFactTypeMapping.TowardsRole == preferredIdentifierRole) { // Make sure this is actually the situation we are trying to handle, since it shouldn't be possible in any other scenario. Debug.Assert(preferredIdentifier.RoleCollection.Count == 1 && preferredIdentifierFactTypeMapping.MappingDepth == MappingDepth.Deep); // UNDONE: Would we ever want to use a depth other than shallow here? Probably not, but it might be worth looking in to. FactTypeMappingFlags currentFlags = preferredIdentifierFactTypeMapping.Flags; preferredIdentifierFactTypeMapping = new FactTypeMapping(preferredIdentifierFactType, preferredIdentifierFactTypeMapping.TowardsRole, preferredIdentifierFactTypeMapping.FromRole, (currentFlags & FactTypeMappingFlags.Subtype) | GetFlags(false, 0 != (currentFlags & FactTypeMappingFlags.TowardsValueType), 0 != (currentFlags & FactTypeMappingFlags.TowardsRoleMandatory), 0 != (currentFlags & FactTypeMappingFlags.TowardsRoleImpliedMandatory), 0 != (currentFlags & FactTypeMappingFlags.FromValueType), 0 != (currentFlags & FactTypeMappingFlags.FromRoleMandatory), 0 != (currentFlags & FactTypeMappingFlags.FromRoleImpliedMandatory))); } else if (preferredIdentifierFactTypeMapping.MappingDepth == MappingDepth.Deep) { // Handle cyclic deep mapping scenario with collapsed entities. // The primary scenario here is: // 1) B is a subtype of A and identified by A's identifier // 2) A and B participate in an objectified 1-1 FactType // 3) The uniqueness constraint on the A role is the preferred identifier // 4) The A role is mandatory // In this case, without this code, you get an assimilation mapping B into A // and mapping A into B. We fix this case by forwarding a shallow mapping, // which generates a reference instad of an assimilation. if (!parentConceptTypeHasDeepAway.HasValue) { ObjectType objectType = ConceptTypeIsForObjectType.GetObjectType(parentConceptType); foreach (Role role in ConceptTypeIsForObjectType.GetObjectType(parentConceptType).PlayedRoleCollection) { FactType factType; FactTypeMapping testMapping; if (null != (factType = role.BinarizedFactType) && factTypeMappings.TryGetValue(factType, out testMapping) && testMapping.MappingDepth == MappingDepth.Deep && testMapping.FromObjectType == objectType) { preferredIdentifierFactTypeMapping = new FactTypeMapping(preferredIdentifierFactType, preferredIdentifierFactTypeMapping.FromRole, preferredIdentifierFactTypeMapping.TowardsRole, preferredIdentifierFactTypeMapping.Flags & ~FactTypeMappingFlags.DeepMapping); parentConceptTypeHasDeepAway = true; break; } } if (!parentConceptTypeHasDeepAway.HasValue) { parentConceptTypeHasDeepAway = false; } } else if (parentConceptTypeHasDeepAway.Value) { preferredIdentifierFactTypeMapping = new FactTypeMapping(preferredIdentifierFactType, preferredIdentifierFactTypeMapping.FromRole, preferredIdentifierFactTypeMapping.TowardsRole, preferredIdentifierFactTypeMapping.Flags & ~FactTypeMappingFlags.DeepMapping); } } GenerateConceptTypeChildrenForFactTypeMapping(factTypeMappings, parentConceptType, ref parentConceptTypeHasDeepAway, preferredIdentifierFactTypeMapping, factTypePath, isMandatory); } } } // If we created a new concept type child, populate its fact type path. if (newConceptTypeChild != null) { foreach (FactType pathFactType in factTypePath) { ConceptTypeChildHasPathFactType conceptTypeChildHasPathFactType = new ConceptTypeChildHasPathFactType(newConceptTypeChild, pathFactType); } } // Pop the current fact type off of the path. Debug.Assert(factTypePath[factTypePath.Count - 1] == factTypeMapping.FactType, "Fact type path stack is corrupt."); factTypePath.RemoveAt(factTypePath.Count - 1); }
/// <summary> /// for regular relationships /// </summary> /// <param name="relation"></param> /// <param name="source"></param> /// <param name="target"></param> /// <param name="notifyAdded"></param> /// <param name="associationCounter"></param> /// <returns></returns> private static bool CreateBinaryAssociation(ConceptTypeChild relation, ConceptType source, ConceptType target, INotifyElementAdded notifyAdded, ref int associationCounter) { if (BinaryAssociationHasConceptTypeChild.GetBinaryAssociation(relation).Count > 0) { //it has already been created return(true); } else if (EntityTypeIsPrimarilyForConceptType.GetEntityType(target) != null) { #region create association BinaryAssociation b = new BinaryAssociation(relation.Store, new PropertyAssignment[] { new PropertyAssignment(BinaryAssociation.NumberDomainPropertyId, associationCounter++) }); //new BinaryAssociationHasConceptTypeChild(b, relation); BinaryAssociationHasConceptTypeChild.GetConceptTypeChildPath(b).Add(relation); Role r1 = new Role(relation.Store, new PropertyAssignment[] { new PropertyAssignment(Role.PredicateTextDomainPropertyId, source.Name) }); Role r2 = new Role(relation.Store, new PropertyAssignment[] { new PropertyAssignment(Role.PredicateTextDomainPropertyId, target.Name) }); b.RoleCollection.Add(r1); b.RoleCollection.Add(r2); EntityType sourceEntity = EntityTypeIsPrimarilyForConceptType.GetEntityType(source); EntityType targetEntity = EntityTypeIsPrimarilyForConceptType.GetEntityType(target); sourceEntity.RoleCollection.Add(r1); targetEntity.RoleCollection.Add(r2); sourceEntity.BarkerErModel.BinaryAssociationCollection.Add(b); #endregion //determine whether roles are mandatory or optional List <ConceptTypeChild> links = new List <ConceptTypeChild>(1); links.Add(relation); r1.IsMandatory = AllStepsMandatory(targetEntity, links); if (relation is ConceptTypeAssimilatesConceptType) { r2.IsMandatory = AllStepsMandatory(sourceEntity, links); } #region determine whether roles are multivalued or not - and possibly rename ORMCore.ObjectType sourceObjectType = ConceptTypeIsForObjectType.GetObjectType(source); ORMCore.ObjectType targetObjectType = ConceptTypeIsForObjectType.GetObjectType(target); ORMCore.UniquenessConstraint uSource = null, uTarget = null; foreach (ORMCore.FactType factType in ConceptTypeChildHasPathFactType.GetPathFactTypeCollection(relation)) { Debug.Assert(factType.RoleCollection.Count == 2, "Error when mapping to Barker ER; the fact type is not binary"); foreach (ORMCore.RoleBase r in factType.RoleCollection) { //need to use RoleBase because we might run into RoleProxy ORMCore.Role role = r.Role; foreach (ORMCore.ConstraintRoleSequence constraintRoleSequence in role.ConstraintRoleSequenceCollection) { ORMCore.UniquenessConstraint uninquenessConstraint = constraintRoleSequence as ORMCore.UniquenessConstraint; if (uninquenessConstraint != null && //check that it's a uniqueness constraint uninquenessConstraint.Modality == ORMCore.ConstraintModality.Alethic && //check it's alethic uninquenessConstraint.IsInternal) //check it's internal { if (role.RolePlayer == sourceObjectType) { uSource = uninquenessConstraint; } if (role.RolePlayer == targetObjectType) { uTarget = uninquenessConstraint; } } } } //name the roles properly //TODO this is a hack; proper name generation is yet to be implemented foreach (ORMCore.ReadingOrder order in factType.ReadingOrderCollection) { string text = order.ReadingText; int first = text.IndexOf('}') + 1; text = text.Substring(first, text.LastIndexOf('{') - first); text = text.Trim(); if (!string.IsNullOrEmpty(text) && order.RoleCollection != null && order.RoleCollection.Count > 0 && order.RoleCollection[0].Role != null) { ORMCore.ObjectType o = order.RoleCollection[0].Role.RolePlayer; if (o == sourceObjectType) { r1.PredicateText = text; } else if (o == targetObjectType) { r2.PredicateText = text; } } } } if (uSource != null && uSource == uTarget) { //it's many-to-many r1.IsMultiValued = true; r2.IsMultiValued = true; } else if (uSource == null || uTarget == null) { //it's one-to-many r1.IsMultiValued = uSource != null; r2.IsMultiValued = uTarget != null; } else if (uSource != null && uTarget != null) { //it's one-to-one r1.IsMultiValued = false; r2.IsMultiValued = false; } else { Debug.Fail("Found a fact type with no uniqueness constraints!"); } #endregion #region primary id? foreach (Uniqueness u in UniquenessIncludesConceptTypeChild.GetUniquenessCollection(relation)) { if (u.IsPreferred) { r1.IsPrimaryIdComponent = true; break; } } #endregion //notify elements added if (notifyAdded != null) { notifyAdded.ElementAdded(b, true); notifyAdded.ElementAdded(r1, true); notifyAdded.ElementAdded(r2, true); } return(true); } else { //should not create binary association in this case return(false); } }