Esempio n. 1
0
		/// <summary>
		/// Determins wheather or not an object type has any possible (potential or decided)
		/// deep fact type mappings away from it.
		/// </summary>
		/// <param name="objectType">The object type to consider</param>
		/// <param name="excludedFactType">The fact type to ignore.  This parameter may be null.</param>
		/// <param name="decidedFactTypeMappings">The decided <see cref="FactTypeMapping"/> objects.</param>
		/// <param name="undecidedFactTypeMappings">The undecided <see cref="FactTypeMapping"/> possibilities.</param>
		/// <returns>True if objectType has possible deep mappings away from it, otherwise false.</returns>
		private bool ObjectTypeHasPossibleDeepMappingsAway(ObjectType objectType, FactType excludedFactType, FactTypeMappingDictionary decidedFactTypeMappings, FactTypeMappingListDictionary undecidedFactTypeMappings)
		{
			LinkedElementCollection<Role> rolesPlayed = ObjectTypePlaysRole.GetPlayedRoleCollection(objectType);

			foreach (Role rolePlayed in rolesPlayed)
			{
				// NOTE: We don't need the ShouldIgnoreFactType filter here, because fact types that we want to ignore won't be in the dictionaries in the first place.
				FactType factType = rolePlayed.BinarizedFactType;

				if (factType == excludedFactType)
				{
					continue;
				}

				FactTypeMapping decidedFactTypeMapping;
				bool decidedFactTypeMappingExists = decidedFactTypeMappings.TryGetValue(factType, out decidedFactTypeMapping);
				FactTypeMappingList potentialFactTypeMappings;
				bool potentialFactTypeMappingsExist = undecidedFactTypeMappings.TryGetValue(factType, out potentialFactTypeMappings);

				// If there's a decided deep fact type mapping away from objectType...
				if (decidedFactTypeMappingExists && decidedFactTypeMapping.MappingDepth == MappingDepth.Deep && decidedFactTypeMapping.FromObjectType == objectType)
				{
					return true;
				}
				else if (potentialFactTypeMappingsExist)
				{
					foreach (FactTypeMapping potentialFactTypeMapping in potentialFactTypeMappings)
					{
						// If there's a potential deep fact type mapping away from objectType...
						if (potentialFactTypeMapping.MappingDepth == MappingDepth.Deep && potentialFactTypeMapping.FromObjectType == objectType)
						{
							return true;
						}
					}
				}
			}

			return false;
		}
Esempio n. 2
0
		/// <summary>
		/// Generates the <see cref="ConceptTypeChild">concept type children</see> for each
		/// <see cref="ConceptType"/> in the <see cref="AbstractionModel">OIAL model</see>.
		/// </summary>
		/// <param name="factTypeMappings">
		/// The set of all decided <see cref="FactTypeMapping">fact type mappings</see>.
		/// </param>
		private void GenerateConceptTypeChildren(FactTypeMappingDictionary factTypeMappings)
		{
			List<FactType> factTypePath = new List<FactType>();

			foreach (ConceptType conceptType in this.AbstractionModel.ConceptTypeCollection)
			{
				ObjectType objectType = ConceptTypeIsForObjectType.GetObjectType(conceptType);
				bool? conceptTypeHasDeepMappingAway = null;

				// NOTE: We don't need the ShouldIgnoreObjectType filter here, because object
				// types that we want to ignore won't be in the OIAL model in the first place.

				foreach (Role playedRole in objectType.PlayedRoleCollection)
				{
					// NOTE: We don't need the ShouldIgnoreFactType filter here, because fact types that
					// we want to ignore won't be in the set of fact type mappings in the first place.
					FactType playedFactType = playedRole.BinarizedFactType;

					FactTypeMapping factTypeMapping;

					if (factTypeMappings.TryGetValue(playedFactType, out factTypeMapping) &&
						factTypeMapping.TowardsRole == playedRole)
					{
						// The fact type has a mapping and that mapping is towards the role played by
						// this concept type, so we need to generate concept type children for it.
						GenerateConceptTypeChildrenForFactTypeMapping(factTypeMappings, conceptType, ref conceptTypeHasDeepMappingAway, factTypeMapping, factTypePath, true);
					}
				}
			}
		}
Esempio n. 3
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);
		}