Ejemplo n.º 1
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);
		}
Ejemplo n.º 2
0
		/// <summary>
		/// Determines the obvious fact type mappings, and all other potential mappings.
		/// </summary>
		/// <param name="modelFactTypes">The <see cref="FactType"/> objects of the model</param>
		/// <param name="decidedManyToOneFactTypeMappings">The decided many-to-one <see cref="FactTypeMapping"/> objects.</param>
		/// <param name="decidedOneToOneFactTypeMappings">The decided one-to-one <see cref="FactTypeMapping"/> objects.</param>
		/// <param name="undecidedOneToOneFactTypeMappings">The undecided <see cref="FactTypeMapping"/> possibilities.</param>
		private void PerformInitialFactTypeMappings(LinkedElementCollection<FactType> modelFactTypes, FactTypeMappingDictionary decidedManyToOneFactTypeMappings, FactTypeMappingDictionary decidedOneToOneFactTypeMappings, FactTypeMappingListDictionary undecidedOneToOneFactTypeMappings)
		{
			// For each fact type in the model...
			foreach (FactType factType in modelFactTypes)
			{
				if (ShouldIgnoreFactType(factType))
				{
					continue;
				}
				SubtypeFact subtypeFact = factType as SubtypeFact;

				// If it's a subtype relation...
				MandatoryConstraint mandatory;
				if (subtypeFact != null)
				{
					Role subtypeRole = subtypeFact.SubtypeRole;
					Role supertypeRole = subtypeFact.SupertypeRole;
					mandatory = supertypeRole.SingleRoleAlethicMandatoryConstraint; // Note that the only way to get a mandatory on the supertype role is with an implied mandatory, verified explicitly below

					// Map deeply toward the supertype.
					FactTypeMapping factTypeMapping = new FactTypeMapping(
						subtypeFact,
						subtypeRole,
						supertypeRole,
						FactTypeMappingFlags.Subtype | FactTypeMappingFlags.DeepMapping | FactTypeMappingFlags.FromRoleMandatory | ((mandatory != null && mandatory.IsImplied) ? FactTypeMappingFlags.TowardsRoleMandatory | FactTypeMappingFlags.TowardsRoleImpliedMandatory : FactTypeMappingFlags.None) | (subtypeRole.RolePlayer.IsValueType ? FactTypeMappingFlags.FromValueType | FactTypeMappingFlags.TowardsValueType : FactTypeMappingFlags.None));
					decidedOneToOneFactTypeMappings.Add(subtypeFact, factTypeMapping);
				}
				else
				{
					LinkedElementCollection<RoleBase> roles = factType.RoleCollection;

					Debug.Assert(roles.Count == 2 && (factType.Objectification == null || factType.UnaryRole != null), "Non-binarized fact types should have been filtered out already.");

					Role firstRole = roles[0].Role;
					Role secondRole = roles[1].Role;
					ObjectType firstRolePlayer = firstRole.RolePlayer;
					ObjectType secondRolePlayer = secondRole.RolePlayer;

					UniquenessConstraint firstRoleUniquenessConstraint = (UniquenessConstraint)firstRole.SingleRoleAlethicUniquenessConstraint;
					UniquenessConstraint secondRoleUniquenessConstraint = (UniquenessConstraint)secondRole.SingleRoleAlethicUniquenessConstraint;
					
					bool firstRolePlayerIsValueType = firstRolePlayer.IsValueType;
					bool secondRolePlayerIsValueType = secondRolePlayer.IsValueType;
					
					bool firstRoleIsUnique = (firstRoleUniquenessConstraint != null);
					bool secondRoleIsUnique = (secondRoleUniquenessConstraint != null);
					
					bool firstRoleIsMandatory = null != (mandatory = firstRole.SingleRoleAlethicMandatoryConstraint);
					bool firstRoleIsImplicitlyMandatory = firstRoleIsMandatory && mandatory.IsImplied;
					bool firstRoleIsExplicitlyMandatory = firstRoleIsMandatory && !firstRoleIsImplicitlyMandatory;
					bool secondRoleIsMandatory = null != (mandatory = secondRole.SingleRoleAlethicMandatoryConstraint);
					bool secondRoleIsImplicitlyMandatory = secondRoleIsMandatory && mandatory.IsImplied;
					bool secondRoleIsExplicitlyMandatory = secondRoleIsMandatory && !secondRoleIsImplicitlyMandatory;

					// We don't need to worry about shallow mappings towards preferred identifiers on many-to-ones, since the preferred
					// identifier pattern ensures that these cases will always map towards the object type being identified anyway.

					const int FIRST_SECOND_SHALLOW = 1;
					const int FIRST_SECOND_DEEP = 2;
					const int SECOND_FIRST_SHALLOW = 4;
					const int SECOND_FIRST_DEEP = 8;
					int possibilityBits = 0;
					bool manyToOne = false;

					// If only firstRole is unique...
					if (firstRoleIsUnique && !secondRoleIsUnique)
					{
						// Shallow map toward firstRolePlayer.
						possibilityBits |= SECOND_FIRST_SHALLOW;
						manyToOne = true;
					}
					else if (!firstRoleIsUnique && secondRoleIsUnique) // ...only secondRole is unique...
					{
						// Shallow map toward secondRolePlayer.
						possibilityBits |= FIRST_SECOND_SHALLOW;
						manyToOne = true;
					}
					else if (firstRoleIsUnique && secondRoleIsUnique) // ...both roles are unique...
					{
						// If this is a ring fact type...
						if (firstRolePlayer == secondRolePlayer)
						{
							// If only firstRole is mandatory...
							if (firstRoleIsExplicitlyMandatory && !secondRoleIsExplicitlyMandatory)
							{
								// Shallow map toward firstRolePlayer (mandatory role player).
								possibilityBits |= FIRST_SECOND_SHALLOW;
							}
							else if (!firstRoleIsExplicitlyMandatory && secondRoleIsExplicitlyMandatory) // ...only secondRole is mandatory...
							{
								// Shallow map toward secondRolePlayer (mandatory role player).
								possibilityBits |= SECOND_FIRST_SHALLOW;
							}
							else // ...otherwise...
							{
								// Shallow map toward firstRolePlayer.
								possibilityBits |= FIRST_SECOND_SHALLOW;
							}
						}
						else // ...not a ring fact type...
						{
							// These are used to make sure that we never shallowly map towards a preferred identifier.
							bool firstRoleIsUniqueAndPreferred = firstRoleIsUnique && firstRoleUniquenessConstraint.IsPreferred;
							bool secondRoleIsUniqueAndPreferred = secondRoleIsUnique && secondRoleUniquenessConstraint.IsPreferred;

							// If neither role is mandatory...
							if (!firstRoleIsExplicitlyMandatory && !secondRoleIsExplicitlyMandatory)
							{
								// If firstRole is not preferred...
								if (!firstRoleIsUniqueAndPreferred)
								{
									// Shallow map toward firstRolePlayer.
									possibilityBits |= SECOND_FIRST_SHALLOW;
								}

								// If secondRole is not preferred...
								if (!secondRoleIsUniqueAndPreferred)
								{
									// Shallow map toward secondRolePlayer.
									possibilityBits |= FIRST_SECOND_SHALLOW;
								}
							}
							else if (firstRoleIsExplicitlyMandatory && !secondRoleIsExplicitlyMandatory) // ...only firstRole is mandatory...
							{
								// Note that the first role cannot be be preferred if the second role is not mandatory
								// Shallow map toward firstRolePlayer.
								possibilityBits |= SECOND_FIRST_SHALLOW;
#if FALSE
								// UNDONE: This is a much deeper check for 1-1 patterns off of mandatory constraints. Both this and
								// the current much quicker check are meant to limit permutation checks on patterns where numerous
								// 1-1 fact types reference the same optional role player. Both of these systems are extremely fragile
								// to one of the uses of the value being made mandatory, in which case this loop does not apply.
								// We need to find a quicker mechanism for determining when we should allow an absorption towards
								// a fully optional object type, or some other check to eliminate extremely long chains (these can
								// easily consume all memory on a machine).
								bool allowMappingTowardsOptionalRole = true;
								if (null != (mandatory = secondRolePlayer.ImpliedMandatoryConstraint))
								{
									if (!(secondRoleIsUniqueAndPreferred && factType.ImpliedByObjectification != null))
									{
										foreach (Role testRole in mandatory.RoleCollection)
										{
											if (testRole != secondRole && !ShouldIgnoreFactType((testRole.Proxy ?? (RoleBase)testRole).FactType))
											{
												Role oppositeRole;
												if (testRole.SingleRoleAlethicUniquenessConstraint != null &&
													null != (oppositeRole = testRole.OppositeRoleAlwaysResolveProxy as Role) &&
													null != oppositeRole.SingleRoleAlethicUniquenessConstraint &&
													null != (mandatory = oppositeRole.SingleRoleAlethicMandatoryConstraint) &&
													!mandatory.IsImplied)
												{
													// If there are multiple 1-1 mappings towards an object type with
													// an implied mandatory, then don't consider any mappings towards
													// this entity.
													allowMappingTowardsOptionalRole = false;
													break;
												}
											}
										}
									}
								}

								if (allowMappingTowardsOptionalRole)
#endif // FALSE
								if (null == secondRolePlayer.ImpliedMandatoryConstraint ||
									((secondRoleIsUniqueAndPreferred && !secondRolePlayerIsValueType) || factType.ImpliedByObjectification != null))
								{
									// If secondRole is not preferred...
									if (!secondRoleIsUniqueAndPreferred)
									{
										// Shallow map toward secondRolePlayer.
										possibilityBits |= FIRST_SECOND_SHALLOW;
									}

									// Deep map toward secondRolePlayer.
									possibilityBits |= FIRST_SECOND_DEEP;
								}
							}
							else if (!firstRoleIsExplicitlyMandatory && secondRoleIsExplicitlyMandatory) // ...only secondRole is mandatory...
							{
								// Note that the second role cannot be preferred if the first role is not mandatory
								// Shallow map toward secondRolePlayer.
								possibilityBits |= FIRST_SECOND_SHALLOW;

#if FALSE
								// UNDONE: See comments above, duplicate code switching first and second
								bool allowMappingTowardsOptionalRole = true;
								if (null != (mandatory = firstRolePlayer.ImpliedMandatoryConstraint))
								{
									if (!(firstRoleIsUniqueAndPreferred && factType.ImpliedByObjectification != null))
									{
										foreach (Role testRole in mandatory.RoleCollection)
										{
											if (testRole != firstRole && !ShouldIgnoreFactType((testRole.Proxy ?? (RoleBase)testRole).FactType))
											{
												Role oppositeRole;
												if (testRole.SingleRoleAlethicUniquenessConstraint != null &&
													null != (oppositeRole = testRole.OppositeRoleAlwaysResolveProxy as Role) &&
													null != oppositeRole.SingleRoleAlethicUniquenessConstraint &&
													null != (mandatory = oppositeRole.SingleRoleAlethicMandatoryConstraint) &&
													!mandatory.IsImplied)
												{
													// If there are multiple 1-1 mappings towards an object type with
													// an implied mandatory, then don't consider any mappings towards
													// this entity.
													allowMappingTowardsOptionalRole = false;
													break;
												}
											}
										}
									}
								}

								if (allowMappingTowardsOptionalRole)
#endif // FALSE
								if (null == firstRolePlayer.ImpliedMandatoryConstraint ||
									((firstRoleIsUniqueAndPreferred && !firstRolePlayerIsValueType) || factType.ImpliedByObjectification != null))
								{
									// If firstRole is not preferred...
									if (!firstRoleIsUniqueAndPreferred)
									{
										// Shallow map toward firstRolePlayer.
										possibilityBits |= SECOND_FIRST_SHALLOW;
									}

									// Deep map toward firstRolePlayer.
									possibilityBits |= SECOND_FIRST_DEEP;
								}
							}
							else // ...both roles are mandatory...
							{
								// If firstRole is not preferred...
								if (!firstRoleIsUniqueAndPreferred)
								{
									// Shallow map toward firstRolePlayer.
									possibilityBits |= SECOND_FIRST_SHALLOW;
								}

								// If secondRole is not preferred...
								if (!secondRoleIsUniqueAndPreferred)
								{
									// Shallow map toward secondRolePlayer.
									possibilityBits |= FIRST_SECOND_SHALLOW;
								}

								// Possible deep map toward firstRolePlayer and toward secondRolePlayer
								possibilityBits |= FIRST_SECOND_DEEP | SECOND_FIRST_DEEP;
							}
						}
					}
					Debug.Assert(possibilityBits != 0);
					switch (possibilityBits)
					{
						case FIRST_SECOND_SHALLOW:
							(manyToOne ? decidedManyToOneFactTypeMappings : decidedOneToOneFactTypeMappings).Add(factType, new FactTypeMapping(factType, firstRole, secondRole, GetFlags(false, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory)));
							break;
						case SECOND_FIRST_SHALLOW:
							(manyToOne ? decidedManyToOneFactTypeMappings : decidedOneToOneFactTypeMappings).Add(factType, new FactTypeMapping(factType, secondRole, firstRole, GetFlags(false, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory)));
							break;
						case FIRST_SECOND_DEEP:
							(manyToOne ? decidedManyToOneFactTypeMappings : decidedOneToOneFactTypeMappings).Add(factType, new FactTypeMapping(factType, firstRole, secondRole, GetFlags(true, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory)));
							break;
						case SECOND_FIRST_DEEP:
							(manyToOne ? decidedManyToOneFactTypeMappings : decidedOneToOneFactTypeMappings).Add(factType, new FactTypeMapping(factType, secondRole, firstRole, GetFlags(true, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory)));
							break;
						default:
							{
								// UNDONE: I don't see any reason to use a heavy-weight list structure here. The
								// same information could be stored in an UndecidedFactTypeMapping structure that
								// uses a bit field mechanism similar to this block of code. This would allow us
								// to store the factType/firstRole/secondRole once and interpret the contents based
								// on a single bitfield. In the meantime, keep the list as small as possible.
								int countBits = possibilityBits;
								int count = 0;
								while (countBits != 0)
								{
									if (0 != (countBits & 1))
									{
										++count;
									}
									countBits >>= 1;
								}
								FactTypeMappingList potentialMappingList = new FactTypeMappingList(count);
								count = -1;
								if (0 != (possibilityBits & FIRST_SECOND_SHALLOW))
								{
									potentialMappingList.Add(new FactTypeMapping(factType, firstRole, secondRole, GetFlags(false, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory)));
								}
								if (0 != (possibilityBits & SECOND_FIRST_SHALLOW))
								{
									potentialMappingList.Add(new FactTypeMapping(factType, secondRole, firstRole, GetFlags(false, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory)));
								}
								if (0 != (possibilityBits & FIRST_SECOND_DEEP))
								{
									potentialMappingList.Add(new FactTypeMapping(factType, firstRole, secondRole, GetFlags(true, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory)));
								}
								if (0 != (possibilityBits & SECOND_FIRST_DEEP))
								{
									potentialMappingList.Add(new FactTypeMapping(factType, secondRole, firstRole, GetFlags(true, secondRolePlayerIsValueType, secondRoleIsMandatory, secondRoleIsImplicitlyMandatory, firstRolePlayerIsValueType, firstRoleIsMandatory, firstRoleIsImplicitlyMandatory)));
								}
								undecidedOneToOneFactTypeMappings.Add(factType, potentialMappingList);
								break;
							}
					}
				}
			}
		}
Ejemplo n.º 3
0
                /// <summary>
                /// If the number of undecided elements is unreasonably high,
                /// then apply incrementally more stringent requirements for
                /// deciding fact type mappings until we have a reasonable number.
                /// </summary>
                public void EnsureReasonablePermutations(FactTypeMappingListDictionary allUndecidedMappings, FactTypeMappingDictionary allPredecidedMappings, FactTypeMappingDictionary allDecidedMappings)
                {
                    FactTypeMappingListList undecidedMappings = myUndecidedOneToOneFactTypeMappings;
                    double maxPermutations = CalculateMaxNumberOfPermutations(undecidedMappings);

                    if (maxPermutations > MaxReasonablePermutations)
                    {
                        int undecidedMappingCount = undecidedMappings.Count;
                        Predicate <FactTypeMapping>[] reductionConditions = ReductionConditions;
                        if (reductionConditions == null)
                        {
                            // Note that there is intentionally a lot of duplication in
                            // these routines. An earlier design attempted to call previous
                            // conditions along with later ones, but this resulted in a much
                            // more complicated algorithm and multiple calls. The algorithm
                            // was simplified in exchange for making these condition routines
                            // more complicated.
                            reductionConditions = new Predicate <FactTypeMapping>[] {
                                delegate(FactTypeMapping mapping)
                                {
                                    // If the fact type has a single non-mandatory value type
                                    // then do not map towards the value type.
                                    FactTypeMappingFlags mappingFlags = mapping.Flags;
                                    if ((mappingFlags & (FactTypeMappingFlags.TowardsValueType | FactTypeMappingFlags.FromValueType)) == (FactTypeMappingFlags.TowardsValueType))
                                    {
                                        if (0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleMandatory))
                                        {
                                            return(0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleImpliedMandatory));
                                        }
                                        return(true);
                                    }
                                    return(false);
                                },
                                delegate(FactTypeMapping mapping)
                                {
                                    // If the fact type has an unbalanced mandatory and is not a subtype,
                                    // then map towards the mandatory.
                                    FactTypeMappingFlags mappingFlags = mapping.Flags;
                                    if (FactTypeMappingFlags.FromRoleMandatory == (mappingFlags & (FactTypeMappingFlags.FromRoleMandatory | FactTypeMappingFlags.FromRoleImpliedMandatory)) &&
                                        0 == (mappingFlags & FactTypeMappingFlags.Subtype) &&
                                        FactTypeMappingFlags.TowardsRoleMandatory != (mappingFlags & (FactTypeMappingFlags.TowardsRoleMandatory | FactTypeMappingFlags.TowardsRoleImpliedMandatory)))
                                    {
                                        return(true);
                                    }

                                    // Duplicate previous ValueType check
                                    if ((mappingFlags & (FactTypeMappingFlags.TowardsValueType | FactTypeMappingFlags.FromValueType)) == (FactTypeMappingFlags.TowardsValueType))
                                    {
                                        if (0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleMandatory))
                                        {
                                            return(0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleImpliedMandatory));
                                        }
                                        return(true);
                                    }
                                    return(false);
                                },
                                delegate(FactTypeMapping mapping)
                                {
                                    // Map away from a preferred identifier. This is not a cumulative test, and is ignored for later conditions.
                                    FactTypeMappingFlags mappingFlags = mapping.Flags;
                                    if (0 == (mappingFlags & FactTypeMappingFlags.FromPreferredIdentifier))
                                    {
                                        return(true);
                                    }

                                    // Duplicate unbalanced ValueType and unbalanced mandatory checks
                                    if (FactTypeMappingFlags.FromRoleMandatory == (mappingFlags & (FactTypeMappingFlags.FromRoleMandatory | FactTypeMappingFlags.FromRoleImpliedMandatory)) &&
                                        0 == (mappingFlags & FactTypeMappingFlags.Subtype) &&
                                        FactTypeMappingFlags.TowardsRoleMandatory != (mappingFlags & (FactTypeMappingFlags.TowardsRoleMandatory | FactTypeMappingFlags.TowardsRoleImpliedMandatory)))
                                    {
                                        return(true);
                                    }
                                    if ((mappingFlags & (FactTypeMappingFlags.TowardsValueType | FactTypeMappingFlags.FromValueType)) == (FactTypeMappingFlags.TowardsValueType))
                                    {
                                        if (0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleMandatory))
                                        {
                                            return(0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleImpliedMandatory));
                                        }
                                        return(true);
                                    }
                                    return(false);
                                },
                                delegate(FactTypeMapping mapping)
                                {
                                    // Prefer a shallow mapping.
                                    FactTypeMappingFlags mappingFlags = mapping.Flags;
                                    if (0 != (mappingFlags & FactTypeMappingFlags.DeepMapping))
                                    {
                                        return(true);
                                    }

                                    // Duplicate unbalanced ValueType and unbalanced mandatory checks
                                    if (FactTypeMappingFlags.FromRoleMandatory == (mappingFlags & (FactTypeMappingFlags.FromRoleMandatory | FactTypeMappingFlags.FromRoleImpliedMandatory)) &&
                                        0 == (mappingFlags & FactTypeMappingFlags.Subtype) &&
                                        FactTypeMappingFlags.TowardsRoleMandatory != (mappingFlags & (FactTypeMappingFlags.TowardsRoleMandatory | FactTypeMappingFlags.TowardsRoleImpliedMandatory)))
                                    {
                                        return(true);
                                    }
                                    if ((mappingFlags & (FactTypeMappingFlags.TowardsValueType | FactTypeMappingFlags.FromValueType)) == (FactTypeMappingFlags.TowardsValueType))
                                    {
                                        if (0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleMandatory))
                                        {
                                            return(0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleImpliedMandatory));
                                        }
                                        return(true);
                                    }
                                    return(false);
                                },
                                delegate(FactTypeMapping mapping)
                                {
                                    // If we have too many permutations then just map towards the first role.
                                    // Yes, this is completely arbitrary, but getting anywhere past item 2 on
                                    // this list will be extremely rarely and represents truly pathological cases.

                                    // Perform previous flag-based checks first.
                                    FactTypeMappingFlags mappingFlags = mapping.Flags;
                                    if (0 != (mappingFlags & FactTypeMappingFlags.DeepMapping))
                                    {
                                        return(true);
                                    }
                                    if (FactTypeMappingFlags.FromRoleMandatory == (mappingFlags & (FactTypeMappingFlags.FromRoleMandatory | FactTypeMappingFlags.FromRoleImpliedMandatory)) &&
                                        0 == (mappingFlags & FactTypeMappingFlags.Subtype) &&
                                        FactTypeMappingFlags.TowardsRoleMandatory != (mappingFlags & (FactTypeMappingFlags.TowardsRoleMandatory | FactTypeMappingFlags.TowardsRoleImpliedMandatory)))
                                    {
                                        return(true);
                                    }
                                    if ((mappingFlags & (FactTypeMappingFlags.TowardsValueType | FactTypeMappingFlags.FromValueType)) == (FactTypeMappingFlags.TowardsValueType))
                                    {
                                        if (0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleMandatory))
                                        {
                                            return(0 != (mappingFlags & FactTypeMappingFlags.TowardsRoleImpliedMandatory));
                                        }
                                        return(true);
                                    }
                                    Role role = mapping.TowardsRole;
                                    return(0 != mapping.FactType.RoleCollection.IndexOf((RoleBase)role.Proxy ?? role));
                                },
                            };
                            ReductionConditions = reductionConditions;
                        }
                        FactTypeMappingList decidedMappings = myPredecidedOneToOneFactTypeMappings;
                        for (int maxReduction = 0; maxReduction < reductionConditions.Length; ++maxReduction)
                        {
                            for (int undecidedMappingIndex = undecidedMappingCount - 1; undecidedMappingIndex >= 0; --undecidedMappingIndex)
                            {
                                FactTypeMappingList testMappings = undecidedMappings[undecidedMappingIndex];
                                int testMappingCount             = testMappings.Count;
                                // Note that the max length of this list is four (shallow and deep both directions)
                                FactTypeMapping singleMapping = null;
                                for (int i = 0; i < testMappingCount; ++i)
                                {
                                    FactTypeMapping testMapping = testMappings[i];
                                    if (!reductionConditions[maxReduction](testMapping))
                                    {
                                        // This test mapping is not filtered, allow it
                                        if (singleMapping == null)
                                        {
                                            singleMapping = testMapping;
                                        }
                                        else
                                        {
                                            singleMapping = null;
                                            break;
                                        }
                                    }
                                }
                                if (singleMapping != null)
                                {
                                    decidedMappings.Add(singleMapping);
                                    undecidedMappings.RemoveAt(undecidedMappingIndex);
                                    --undecidedMappingCount;
                                    maxPermutations /= testMappingCount;
                                    FactType factTypeKey = singleMapping.FactType;
                                    allUndecidedMappings.Remove(factTypeKey);
                                    allPredecidedMappings.Add(factTypeKey, singleMapping);
                                    allDecidedMappings.Add(factTypeKey, singleMapping);
                                }
                            }
                            if (maxPermutations <= MaxReasonablePermutations)
                            {
                                break;
                            }
                        }
                    }
                }