public FactTypeChainer(FactTypeMappingDictionary predecidedManyToOneFactTypeMappings, FactTypeMappingDictionary predecidedOneToOneFactTypeMappings, FactTypeMappingListDictionary undecidedOneToOneFactTypeMappings) { myChains = new ChainList(); myPredecidedManyToOneFactTypeMappings = predecidedManyToOneFactTypeMappings; myPredecidedOneToOneFactTypeMappings = predecidedOneToOneFactTypeMappings; myUndecidedOneToOneFactTypeMappings = undecidedOneToOneFactTypeMappings; }
public FactTypeMappingDictionary(FactTypeMappingDictionary values) : base(values.Count) { foreach (KeyValuePair <FactType, FactTypeMapping> pair in values) { Add(pair.Key, pair.Value); } }
public int Run(FactTypeMappingDictionary allDecidedMappings) { BuildChains(); ReduceChains(allDecidedMappings); // Delete empty chains and find the largest chain. int largestChainCount = 0; for (int i = myChains.Count - 1; i >= 0; --i) { Chain chain = myChains[i]; if (chain.UndecidedOneToOneFactTypeMappings.Count == 0) { myChains.RemoveAt(i); continue; } int chainCount = chain.OneToOneFactTypeCount; if (chainCount > largestChainCount) { largestChainCount = chainCount; } } return largestChainCount; }
/// <summary> /// Maps one-to-one fact types with two simple alethic mandatories away from the object type that has no possible /// (potential or decided) deep mappings away from it. If both role players meet this criteria then no action is /// taken. /// </summary> /// <param name="decidedOneToOneFactTypeMappings">The decided <see cref="FactTypeMapping"/> objects.</param> /// <param name="undecidedOneToOneFactTypeMappings">The undecided <see cref="FactTypeMapping"/> posibilities.</param> /// <returns>The number of previously potential one-to-one fact type mappings that are now decided.</returns> private int MapTrivialOneToOneFactTypesWithTwoMandatories(FactTypeMappingDictionary decidedOneToOneFactTypeMappings, FactTypeMappingListDictionary undecidedOneToOneFactTypeMappings) { List<FactType> factTypesPendingDeletion = new List<FactType>(); foreach (KeyValuePair<FactType, FactTypeMappingList> undecidedPair in undecidedOneToOneFactTypeMappings) { FactType factType = undecidedPair.Key; FactTypeMappingList potentialFactTypeMappings = undecidedPair.Value; LinkedElementCollection<RoleBase> roles = factType.RoleCollection; Debug.Assert(roles.Count == 2, "All fact type mappings should be for fact types with exactly two roles."); Role firstRole = roles[0].Role; Role secondRole = roles[1].Role; ObjectType firstRolePlayer = firstRole.RolePlayer; ObjectType secondRolePlayer = secondRole.RolePlayer; // If this is a one-to-one fact type with two simple alethic mandatories... if (firstRole.SingleRoleAlethicMandatoryConstraint != null && secondRole.SingleRoleAlethicMandatoryConstraint != null) { FactTypeMapping deepMappingTowardsFirstRole = null; FactTypeMapping deepMappingTowardsSecondRole = null; // Find our potential deep mappings. foreach (FactTypeMapping potentialFactTypeMapping in potentialFactTypeMappings) { if (potentialFactTypeMapping.MappingDepth == MappingDepth.Deep) { if (potentialFactTypeMapping.TowardsRole == firstRole) { deepMappingTowardsFirstRole = potentialFactTypeMapping; } else { Debug.Assert(potentialFactTypeMapping.TowardsRole == secondRole); deepMappingTowardsSecondRole = potentialFactTypeMapping; } } } bool firstRolePlayerHasPossibleDeepMappingsAway = ObjectTypeHasPossibleDeepMappingsAway(firstRolePlayer, factType, decidedOneToOneFactTypeMappings, undecidedOneToOneFactTypeMappings); bool secondRolePlayerHasPossibleDeepMappingsAway = ObjectTypeHasPossibleDeepMappingsAway(secondRolePlayer, factType, decidedOneToOneFactTypeMappings, undecidedOneToOneFactTypeMappings); // UNDONE: We need to do cycle checking at or before this point, since otherwise this can create a decided deep mapping cycle. // If secondRolePlayer has no possible deep mappings away from it, and firstRolePlayer does... if (firstRolePlayerHasPossibleDeepMappingsAway && !secondRolePlayerHasPossibleDeepMappingsAway) { // Make sure that this deep mapping was one of our potentials. if (deepMappingTowardsFirstRole != null) { Debug.Assert(firstRole.SingleRoleAlethicUniquenessConstraint != null); // Make sure we're not going towards a preferred identifier. Doing so is valid, and sometimes optimal, // but not always, hence the permuter needs to consider it. if (!firstRole.SingleRoleAlethicUniquenessConstraint.IsPreferred) { // Deep map toward firstRolePlayer decidedOneToOneFactTypeMappings.Add(factType, deepMappingTowardsFirstRole); factTypesPendingDeletion.Add(factType); } } } // ...and vice-versa... else if (!firstRolePlayerHasPossibleDeepMappingsAway && secondRolePlayerHasPossibleDeepMappingsAway) { // Make sure that this deep mapping was one of our potentials. if (deepMappingTowardsSecondRole != null) { Debug.Assert(secondRole.SingleRoleAlethicUniquenessConstraint != null); // Make sure we're not going towards a preferred identifier. Doing so is valid, and sometimes optimal, // but not always, hence the permuter needs to consider it. if (!secondRole.SingleRoleAlethicUniquenessConstraint.IsPreferred) { // Deep map toward secondRolePlayer decidedOneToOneFactTypeMappings.Add(factType, deepMappingTowardsSecondRole); factTypesPendingDeletion.Add(factType); } } } } } // Delete each undecided (now decided) fact type mapping marked for deletion. foreach (FactType key in factTypesPendingDeletion) { undecidedOneToOneFactTypeMappings.Remove(key); } return factTypesPendingDeletion.Count; }
/// <summary> /// Filters out deep potential mappings that are from an <see cref="ObjectType"/> that already has a decided deep /// mapping from it. /// </summary> /// <param name="decidedOneToOneFactTypeMappings">The decided <see cref="FactTypeMapping"/> objects.</param> /// <param name="undecidedOneToOneFactTypeMappings">The undecided <see cref="FactTypeMapping"/> possibilities.</param> private void RemoveImpossiblePotentialFactTypeMappings(FactTypeMappingDictionary decidedOneToOneFactTypeMappings, FactTypeMappingListDictionary undecidedOneToOneFactTypeMappings) { Dictionary<ObjectType, object> deeplyMappedObjectTypes = new Dictionary<ObjectType, object>(decidedOneToOneFactTypeMappings.Count + undecidedOneToOneFactTypeMappings.Count); // For each decided fact type mapping... foreach (FactTypeMapping factTypeMapping in decidedOneToOneFactTypeMappings.Values) { // If it's a deep mapping... if (factTypeMapping.MappingDepth == MappingDepth.Deep) { deeplyMappedObjectTypes[factTypeMapping.FromObjectType] = null; } } List<FactType> factsPendingDeletion = new List<FactType>(); foreach (KeyValuePair<FactType, FactTypeMappingList> undecidedFactTypeMapping in undecidedOneToOneFactTypeMappings) { FactType factType = undecidedFactTypeMapping.Key; FactTypeMappingList potentialFactTypeMappings = undecidedFactTypeMapping.Value; // For each potential fact type mapping... for (int i = potentialFactTypeMappings.Count - 1; i >= 0; --i) { FactTypeMapping potentialFactTypeMapping = potentialFactTypeMappings[i]; // If it is maped away from an ObjectType that is already determined to be mapped elsewhere... if (potentialFactTypeMapping.MappingDepth == MappingDepth.Deep && deeplyMappedObjectTypes.ContainsKey(potentialFactTypeMapping.FromObjectType)) { // Remove it as a possibility. potentialFactTypeMappings.RemoveAt(i); } } Debug.Assert(potentialFactTypeMappings.Count > 0); // If there is only one possibility left... if (potentialFactTypeMappings.Count == 1) { // Mark it decided. decidedOneToOneFactTypeMappings.Add(factType, potentialFactTypeMappings[0]); factsPendingDeletion.Add(factType); } } // Delete each undecided (now decided) fact type mapping marked for deletion. foreach (FactType key in factsPendingDeletion) { undecidedOneToOneFactTypeMappings.Remove(key); } }
/// <summary> /// Runs various algorithms on the undecided fact type mappings in an attempt to decide as many as possible. /// </summary> /// <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 FilterFactTypeMappings(FactTypeMappingDictionary decidedManyToOneFactTypeMappings, FactTypeMappingDictionary decidedOneToOneFactTypeMappings, FactTypeMappingListDictionary undecidedOneToOneFactTypeMappings) { bool changed; do { RemoveImpossiblePotentialFactTypeMappings(decidedOneToOneFactTypeMappings, undecidedOneToOneFactTypeMappings); changed = MapTrivialOneToOneFactTypesWithTwoMandatories(decidedOneToOneFactTypeMappings, undecidedOneToOneFactTypeMappings) > 0; } while (changed); }
/// <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; } } } } }
/// <summary> /// Transforms the data in <see cref="ORMModel"/> into this <see cref="AbstractionModel"/>. /// </summary> private void TransformORMtoOial() { ORMModel model = this.ORMModel; LinkedElementCollection<FactType> modelFactTypes = model.FactTypeCollection; FactTypeMappingDictionary decidedManyToOneFactTypeMappings = new FactTypeMappingDictionary(); FactTypeMappingDictionary decidedOneToOneFactTypeMappings = new FactTypeMappingDictionary(); FactTypeMappingListDictionary undecidedOneToOneFactTypeMappings = new FactTypeMappingListDictionary(); PerformInitialFactTypeMappings(modelFactTypes, decidedManyToOneFactTypeMappings, decidedOneToOneFactTypeMappings, undecidedOneToOneFactTypeMappings); FilterFactTypeMappings(decidedManyToOneFactTypeMappings, decidedOneToOneFactTypeMappings, undecidedOneToOneFactTypeMappings); FactTypeMappingPermuter permuter = new FactTypeMappingPermuter(decidedManyToOneFactTypeMappings, decidedOneToOneFactTypeMappings, undecidedOneToOneFactTypeMappings); FactTypeMappingDictionary decidedFactTypeMappings = permuter.Run(); GenerateOialModel(decidedFactTypeMappings); }
/// <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; } } } }
/// <summary> /// Generages the <see cref="ConceptType"/> objects along with any relationships that they have and adds them to the /// model. /// </summary> /// <param name="factTypeMappings">A dictionary of all the final decided FactTypeMapping objects.</param> private void GenerateConceptTypes(FactTypeMappingDictionary factTypeMappings) { ORMModel model = this.ORMModel; LinkedElementCollection<ObjectType> modelObjectTypes = model.ObjectTypeCollection; AbstractionModel oialModel = this.AbstractionModel; // For each object type in the model... foreach (ObjectType objectType in modelObjectTypes) { if (ShouldIgnoreObjectType(objectType)) { continue; } // If it should have a conctpt type... if (ObjectTypeIsConceptType(objectType, factTypeMappings)) { // Create the ConceptType object. PropertyAssignment name = new PropertyAssignment(ConceptType.NameDomainPropertyId, objectType.Name); ConceptType conceptType = new ConceptType(Store, name); ConceptTypeIsForObjectType conceptTypeIsForObjectType = new ConceptTypeIsForObjectType(conceptType, objectType); // Add it to the model. oialModel.ConceptTypeCollection.Add(conceptType); // If this conceptType is for a ValueType... if (objectType.IsValueType) { InformationTypeFormat valueTypeInformationTypeFormat = InformationTypeFormatIsForValueType.GetInformationTypeFormat(objectType); RoleAssignment conceptTypeRole = new RoleAssignment(InformationType.ConceptTypeDomainRoleId, conceptType); RoleAssignment informationTypeFormat = new RoleAssignment(InformationType.InformationTypeFormatDomainRoleId, valueTypeInformationTypeFormat); RoleAssignment[] roleAssignments = { conceptTypeRole, informationTypeFormat }; PropertyAssignment isMandatory = new PropertyAssignment(InformationType.IsMandatoryDomainPropertyId, true); PropertyAssignment informationTypeNameProperty = new PropertyAssignment(InformationType.NameDomainPropertyId, String.Concat(objectType.Name, "Value")); PropertyAssignment[] informationTypePropertyAssignments = { isMandatory, informationTypeNameProperty }; // ConceptType for conceptType gets an InformationType that references InformationTypeFormat for conceptType. InformationType informationType = new InformationType(Store, roleAssignments, informationTypePropertyAssignments); PropertyAssignment uniquenessNameProperty = new PropertyAssignment(Uniqueness.NameDomainPropertyId, String.Concat(objectType.Name, "Uniqueness")); PropertyAssignment isPreferred = new PropertyAssignment(Uniqueness.IsPreferredDomainPropertyId, true); PropertyAssignment[] uniquenessPropertyAssignments = { uniquenessNameProperty, isPreferred }; // Uniqueness constraint Uniqueness uniqueness = new Uniqueness(Store, uniquenessPropertyAssignments); UniquenessIncludesConceptTypeChild uniquenessIncludesConceptTypeChild = new UniquenessIncludesConceptTypeChild(uniqueness, informationType); conceptType.UniquenessCollection.Add(uniqueness); } } } }
private void GenerateFactTypeMappings(FactTypeMappingDictionary factTypeMappings) { foreach (FactTypeMapping mapping in factTypeMappings.Values) { // Note that there will currently be no existing maps, but this is // likely to change once we do more incremental work. If the FactTypeMapsTowardsRole // instance already exists for this FactType, then the following will throw. // Any role changes here need to properly update the existing link's mapping // pattern properties. This should be done with an OnRolePlayerChanged call // (or a rule) inside FactTypeMapsTowardsRole. FactTypeMapsTowardsRole.Create(mapping.FactType, mapping.TowardsRole, mapping.MappingDepth); } }
/// <summary> /// Generates the <see cref="Uniqueness"/> objects for the <see cref="AbstractionModel"/>. /// </summary> /// <param name="factTypeMappings">The decided <see cref="FactTypeMapping"/> objects.</param> private void GenerateUniqueness(FactTypeMappingDictionary factTypeMappings) { // TODO: clean this up. AbstractionModel oialModel = this.AbstractionModel; // For each concept type in the model... foreach (ConceptType conceptType in oialModel.ConceptTypeCollection) { ObjectType objectType = ConceptTypeIsForObjectType.GetObjectType(conceptType); // For each role played by its object type... foreach (Role role in objectType.PlayedRoleCollection) { if (ShouldIgnoreFactType(role.BinarizedFactType)) { continue; } Role oppositeRole = role.OppositeRoleAlwaysResolveProxy.Role; // For each constraint on the opposite role... foreach (ConstraintRoleSequence constraintRoleSequence in oppositeRole.ConstraintRoleSequenceCollection) { UniquenessConstraint uninquenessConstraint = constraintRoleSequence as UniquenessConstraint; // If it is a uniqueness constraint... if (uninquenessConstraint != null && uninquenessConstraint.Modality == ConstraintModality.Alethic) { if (UniquenessIsForUniquenessConstraint.GetUniqueness(uninquenessConstraint) != null) { continue; } bool hasFactTypeThatShouldBeIgnored = false; bool allChildrenMapTowardObjectType = true; IList<FactType> factTypes = new List<FactType>(); foreach (Role childRole in uninquenessConstraint.RoleCollection) { FactType binarizedFactType = childRole.BinarizedFactType; if (ShouldIgnoreFactType(binarizedFactType)) { hasFactTypeThatShouldBeIgnored = true; break; } FactTypeMapping factTypeMapping = factTypeMappings[binarizedFactType]; if (factTypeMapping.TowardsRole != childRole.OppositeRoleAlwaysResolveProxy.Role) { allChildrenMapTowardObjectType = false; break; } else { factTypes.Add(binarizedFactType); } } if (hasFactTypeThatShouldBeIgnored) { continue; } if (allChildrenMapTowardObjectType) { IList<ConceptTypeChild> conceptTypeChildren = new List<ConceptTypeChild>(); bool skipThisUniquenessConstraint = false; foreach (FactType factType in factTypes) { bool childWasAssimilation = false; bool missedChild = true; foreach (ConceptTypeChild conceptTypeChild in ConceptTypeChildHasPathFactType.GetConceptTypeChild(factType)) { if (conceptTypeChild.Parent != conceptType) { // This ConceptTypeChild is of a different ConceptType, so go on to the next ConceptTypeChild. continue; } if (conceptTypeChild is ConceptTypeAssimilatesConceptType) { childWasAssimilation = true; break; } missedChild = false; conceptTypeChildren.Add(conceptTypeChild); } if (childWasAssimilation) { skipThisUniquenessConstraint = true; break; } if (missedChild) { // We couldn't find a ConceptTypeChild for this FactType, so just bail out. skipThisUniquenessConstraint = true; break; } } if (!skipThisUniquenessConstraint) { PropertyAssignment name = new PropertyAssignment(Uniqueness.NameDomainPropertyId, uninquenessConstraint.Name); PropertyAssignment isPreferred = new PropertyAssignment(Uniqueness.IsPreferredDomainPropertyId, uninquenessConstraint.IsPreferred); PropertyAssignment[] propertyAssignments = { name, isPreferred }; // Create uniquenesss Uniqueness uniqueness = new Uniqueness(Store, propertyAssignments); uniqueness.ConceptType = conceptType; new UniquenessIsForUniquenessConstraint(uniqueness, uninquenessConstraint); foreach (ConceptTypeChild conceptTypeChild in conceptTypeChildren) { UniquenessIncludesConceptTypeChild uniquenessIncludesConceptTypeChild = new UniquenessIncludesConceptTypeChild(uniqueness, conceptTypeChild); } } } } } } } }
/// <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); }
public FactTypeMappingPermuter(FactTypeMappingDictionary predecidedManyToOneFactTypeMappings, FactTypeMappingDictionary predecidedOneToOneFactTypeMappings, FactTypeMappingListDictionary undecidedOneToOneFactTypeMappings) { myPredecidedManyToOneFactTypeMappings = predecidedManyToOneFactTypeMappings; myPredecidedOneToOneFactTypeMappings = predecidedOneToOneFactTypeMappings; myUndecidedOneToOneFactTypeMappings = undecidedOneToOneFactTypeMappings; myDecidedFactTypeMappings = new FactTypeMappingDictionary(predecidedManyToOneFactTypeMappings.Count + predecidedOneToOneFactTypeMappings.Count + undecidedOneToOneFactTypeMappings.Count); foreach (KeyValuePair<FactType, FactTypeMapping> pair in predecidedManyToOneFactTypeMappings) { myDecidedFactTypeMappings.Add(pair.Key, pair.Value); } foreach (KeyValuePair<FactType, FactTypeMapping> pair in predecidedOneToOneFactTypeMappings) { myDecidedFactTypeMappings.Add(pair.Key, pair.Value); } }
/// <summary> /// Apply more stringent criteria to unusually long chains to ensure that /// the permutation process will not explode. /// </summary> private void ReduceChains(FactTypeMappingDictionary allDecidedMappings) { // Make sure all of the chains are of a size that we can actually permute FactTypeMappingDictionary predecidedMappings = myPredecidedOneToOneFactTypeMappings; FactTypeMappingListDictionary undecidedMappings = myUndecidedOneToOneFactTypeMappings; foreach (Chain chain in myChains) { chain.EnsureReasonablePermutations(undecidedMappings, predecidedMappings, allDecidedMappings); } }
/// <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; }
/// <summary> /// Populates this <see cref="AbstractionModel"/> given the decided <see cref="FactTypeMapping"/> objects. /// </summary> /// <param name="factTypeMappings">The decided <see cref="FactTypeMapping"/> objects.</param> private void GenerateOialModel(FactTypeMappingDictionary factTypeMappings) { GenerateInformationTypeFormats(); GenerateConceptTypes(factTypeMappings); GenerateConceptTypeChildren(factTypeMappings); GenerateFactTypeMappings(factTypeMappings); GenerateUniqueness(factTypeMappings); GenerateAssociations(); }
/// <summary> /// Determins wheather an <see cref="ObjectType"/> is destined to be a top-level <see cref="ConceptType"/> or not. /// </summary> /// <param name="objectType">The <see cref="ObjectType"/> to test.</param> /// <param name="factTypeMappings">A dictionary of all the final decided <see cref="FactTypeMapping"/> objects.</param> /// <returns>Returns true if the <see cref="ObjectType"/> is destined to be a top-level <see cref="ConceptType"/>.</returns> private bool ObjectTypeIsTopLevelConceptType(ObjectType objectType, FactTypeMappingDictionary factTypeMappings) { if (ObjectTypeIsConceptType(objectType, factTypeMappings)) { LinkedElementCollection<Role> roles = ObjectTypePlaysRole.GetPlayedRoleCollection(objectType); foreach (Role role in roles) { FactType factType = role.BinarizedFactType; if (ShouldIgnoreFactType(factType)) { continue; } FactTypeMapping factTypeMapping = factTypeMappings[factType]; if (factTypeMapping.FromObjectType == objectType && factTypeMapping.MappingDepth == MappingDepth.Deep) { return false; } } return true; } return false; }
/// <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); } } } }
/// <summary> /// Determins wheather an <see cref="ObjectType"/> should have a <see cref="ConceptType"/> or not. /// </summary> /// <remarks> /// An <see cref="ObjectType"/> should have a <see cref="ConceptType"/> if: /// <list> /// <item><description>It is independent.</description></item> /// <item><description>It is a subtype.</description></item> /// <item><description>It has a <see cref="FactTypeMapping"/> towards it for a <see cref="FactType"/> that is not part of its preferred identifier.</description></item> /// </list> /// </remarks> /// <param name="objectType">The <see cref="ObjectType"/> to test.</param> /// <param name="factTypeMappings">A dictionary of all the final decided <see cref="FactTypeMapping"/> objects.</param> /// <returns>Returns true if the <see cref="ObjectType"/> should have <see cref="ConceptType"/>.</returns> private bool ObjectTypeIsConceptType(ObjectType objectType, FactTypeMappingDictionary factTypeMappings) { // If objectType is independent... if (objectType.TreatAsIndependent) { return true; } foreach (Role role in ObjectTypePlaysRole.GetPlayedRoleCollection(objectType)) { FactType factType = role.BinarizedFactType; if (ShouldIgnoreFactType(factType)) { continue; } // If it is a subtype fact, we need a concept type. Although the algorithm only calls for this in the case // of subtype meta roles, supertype meta roles will always match the patterns below, so we can immediately // return true for them as well. if (factType is SubtypeFact) { return true; } FactTypeMapping factTypeMapping = factTypeMappings[factType]; // If fact type mapping is toward objectType... if (factTypeMapping.TowardsObjectType == objectType) { bool isPartOfPreferredIdentifier = false; foreach (ConstraintRoleSequence constraintRoleSequence in factTypeMapping.FromRole.ConstraintRoleSequenceCollection) { UniquenessConstraint uninquenessConstraint = constraintRoleSequence as UniquenessConstraint; if (uninquenessConstraint != null && uninquenessConstraint.IsPreferred) { isPartOfPreferredIdentifier = true; break; } } if (!isPartOfPreferredIdentifier) { // This FactType is not part of the preferred identifier. return true; } } } return false; }