Example #1
0
        private static void UpdateEntitiesForConceptType(ConceptType conceptType, Predicate <ConceptType> conceptTypeFilter, Predicate <EntityType> entityFilter)
        {
            EntityType primaryEntity = EntityTypeIsPrimarilyForConceptType.GetEntityType(conceptType);

            if (primaryEntity != null && (entityFilter == null || !entityFilter(primaryEntity)))
            {
                UpdateEntityPresentationSize(primaryEntity);
            }
            Predicate <ConceptType> recurseConceptTypeFilter =
                delegate(ConceptType testConceptType)
            {
                return(testConceptType == conceptType ||
                       (conceptTypeFilter != null && conceptTypeFilter(testConceptType)));
            };
            Predicate <EntityType> recurseEntityFilter =
                delegate(EntityType testEntity)
            {
                return(testEntity == primaryEntity);
            };

            foreach (ConceptType relatingConceptType in ConceptTypeRelatesToConceptType.GetRelatingConceptTypeCollection(conceptType))
            {
                if (relatingConceptType == conceptType || (conceptTypeFilter != null && conceptTypeFilter(relatingConceptType)))
                {
                    continue;
                }
                UpdateEntitiesForConceptType(
                    relatingConceptType,
                    recurseConceptTypeFilter,
                    recurseEntityFilter);
            }
            foreach (ConceptType assimilatedConceptType in ConceptTypeAssimilatesConceptType.GetAssimilatedConceptTypeCollection(conceptType))
            {
                if (assimilatedConceptType == conceptType || (conceptTypeFilter != null && conceptTypeFilter(assimilatedConceptType)))
                {
                    continue;
                }
                UpdateEntitiesForConceptType(
                    assimilatedConceptType,
                    recurseConceptTypeFilter,
                    recurseEntityFilter);
            }
        }
        private static void CreateAttributesAndBinaryRelationships(ConceptType conceptType, INotifyElementAdded notifyAdded, ref int associationCounter)
        {
            List <Attribute> attributesForConceptType = new List <Attribute>();

            foreach (InformationType informationType in InformationType.GetLinksToInformationTypeFormatCollection(conceptType))
            {
                attributesForConceptType.Add(CreateAttributeForInformationType(informationType, new Stack <ConceptTypeChild>()));
            }
            foreach (ConceptTypeRelatesToConceptType conceptTypeRelation in ConceptTypeRelatesToConceptType.GetLinksToRelatedConceptTypeCollection(conceptType))
            {
                if (!CreateBinaryAssociation(conceptTypeRelation, conceptType, conceptTypeRelation.RelatedConceptType, notifyAdded, ref associationCounter))
                {
                    //if binary association was not created - let's create an attribute for it
                    attributesForConceptType.AddRange(GetAttributesForConceptTypeRelation(conceptTypeRelation, new Stack <ConceptTypeChild>()));
                }
            }
            foreach (ConceptTypeAssimilatesConceptType conceptTypeAssimilation in ConceptTypeAssimilatesConceptType.GetLinksToAssimilatedConceptTypeCollection(conceptType))
            {
                if (!conceptTypeAssimilation.RefersToSubtype)
                {
                    CreateBinaryAssociation(conceptTypeAssimilation, conceptType, conceptTypeAssimilation.AssimilatedConceptType, notifyAdded, ref associationCounter);
                }
            }


            EntityType conceptTypeEntity = EntityTypeIsPrimarilyForConceptType.GetEntityType(conceptType);

            if (conceptTypeEntity != null)
            {
                conceptTypeEntity.AttributeCollection.AddRange(attributesForConceptType);
                if (notifyAdded != null)
                {
                    foreach (Attribute attr in attributesForConceptType)
                    {
                        notifyAdded.ElementAdded(attr, true);
                    }
                }
            }
        }
        private static bool AllStepsMandatory(EntityType entity, IEnumerable <ConceptTypeChild> links)
        {
            bool        allStepsMandatory = true;
            ConceptType lastTarget        = null;
            bool        firstPass         = true;

            foreach (ConceptTypeChild child in links)
            {
                if (!child.IsMandatory)
                {
                    ConceptTypeAssimilatesConceptType assimilation = child as ConceptTypeAssimilatesConceptType;
                    if (assimilation != null)
                    {
                        // The IsMandatory property applies when stepping parent-to-target, However, stepping target-to-parent
                        // is always considered mandatory. See if we're in this situation.
                        if (firstPass)
                        {
                            lastTarget = EntityTypeIsPrimarilyForConceptType.GetConceptType(entity);
                        }
                        if (lastTarget != null &&
                            lastTarget == assimilation.Target)
                        {
                            lastTarget = assimilation.Parent;
                            firstPass  = false;
                            continue;
                        }
                    }
                    allStepsMandatory = false;
                    break;
                }
                lastTarget = child.Target as ConceptType;
                firstPass  = false;
            }

            return(allStepsMandatory);
        }
Example #4
0
		/// <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);
		}