From: <mcu...@us...> - 2007-08-30 17:24:14
|
Revision: 1101 http://orm.svn.sourceforge.net/orm/?rev=1101&view=rev Author: mcurland Date: 2007-08-30 10:24:00 -0700 (Thu, 30 Aug 2007) Log Message: ----------- Improved top-level concept type and non-top-level concept type count detection used by FactTypeMappingPermuter. Various other bug fixes and tweaks. refs #327 Modified Paths: -------------- trunk/ORMModel/ObjectModel/ObjectType.cs trunk/Oial/ORMOialBridge/ORMOialBridgePermuter.cs trunk/Oial/ORMOialBridge/ORMOialBridgeStructures.cs trunk/Oial/ORMOialBridge/OialModelIsForORMModel.cs Modified: trunk/ORMModel/ObjectModel/ObjectType.cs =================================================================== --- trunk/ORMModel/ObjectModel/ObjectType.cs 2007-08-30 17:21:57 UTC (rev 1100) +++ trunk/ORMModel/ObjectModel/ObjectType.cs 2007-08-30 17:24:00 UTC (rev 1101) @@ -1569,6 +1569,20 @@ } } /// <summary> + /// Indicates if this <see cref="ObjectType"/> is implied independent. + /// </summary> + public bool IsImpliedIndependent() + { + return !this.IsIndependent && this.ImpliedMandatoryConstraint == null && this.AllowIsIndependent(false); + } + /// <summary> + /// Indicates if this <see cref="ObjectType"/> is either implied independent or explicity independent. + /// </summary> + public bool IsAnyIndependent() + { + return this.IsIndependent || this.IsImpliedIndependent(); + } + /// <summary> /// Test if the <see cref="IsIndependent"/> property can be set to true. /// </summary> /// <param name="throwIfFalse">Set to <see langword="true"/> to throw an exception instead of returning false.</param> Modified: trunk/Oial/ORMOialBridge/ORMOialBridgePermuter.cs =================================================================== --- trunk/Oial/ORMOialBridge/ORMOialBridgePermuter.cs 2007-08-30 17:21:57 UTC (rev 1100) +++ trunk/Oial/ORMOialBridge/ORMOialBridgePermuter.cs 2007-08-30 17:24:00 UTC (rev 1101) @@ -113,8 +113,14 @@ Chain chain = new Chain(); myChains.Add(chain); + // Assuming ProcessObjectType works correctly, we will never hit an object type a second time, + // so we can clear the Dictionary here and then use it as a record of all object types in the chain. + visitedObjectTypes.Clear(); + ProcessObjectType(factType.RoleCollection[0].Role.RolePlayer, chain, visitedFactTypes, visitedObjectTypes); + // Record all object types that are in the chain. + chain.ObjectTypes.AddRange(visitedObjectTypes.Keys); } } private void ProcessObjectType(ObjectType objectType, Chain chain, Dictionary<FactType, object> visitedFactTypes, Dictionary<ObjectType, object> visitedObjectTypes) @@ -205,22 +211,14 @@ private readonly FactTypeMappingDictionary myDecidedFactTypeMappings; - // Stores a list of object types that had been considered valid top-level, but was later found to be deeply mapped away - private readonly ObjectTypeDictionary myInvalidObjectTypes; - // A single set of possible fact type mappings represented at a given iteration through all possible fact type mappings - private readonly ObjectTypeDictionary myPossibleTopLevelConceptTypes; - private readonly ObjectTypeDictionary myPossibleConceptTypes; - - public FactTypeMappingPermuter(FactTypeMappingDictionary predecidedManyToOneFactTypeMappings, FactTypeMappingDictionary predecidedOneToOneFactTypeMappings, FactTypeMappingListDictionary undecidedOneToOneFactTypeMappings) { myPredecidedManyToOneFactTypeMappings = predecidedManyToOneFactTypeMappings; myPredecidedOneToOneFactTypeMappings = predecidedOneToOneFactTypeMappings; myUndecidedOneToOneFactTypeMappings = undecidedOneToOneFactTypeMappings; - int oneToOneFactTypeCount = predecidedOneToOneFactTypeMappings.Count + undecidedOneToOneFactTypeMappings.Count; - myDecidedFactTypeMappings = new FactTypeMappingDictionary(predecidedManyToOneFactTypeMappings.Count + oneToOneFactTypeCount); + myDecidedFactTypeMappings = new FactTypeMappingDictionary(predecidedManyToOneFactTypeMappings.Count + predecidedOneToOneFactTypeMappings.Count + undecidedOneToOneFactTypeMappings.Count); foreach (KeyValuePair<FactType, FactTypeMapping> pair in predecidedManyToOneFactTypeMappings) { @@ -230,11 +228,6 @@ { myDecidedFactTypeMappings.Add(pair.Key, pair.Value); } - - // Stores a list of object types that had been considered valid top-level, but was later found to be deeply mapped away - myInvalidObjectTypes = new ObjectTypeDictionary(oneToOneFactTypeCount); - myPossibleTopLevelConceptTypes = new ObjectTypeDictionary(oneToOneFactTypeCount); - myPossibleConceptTypes = new ObjectTypeDictionary(oneToOneFactTypeCount); } /// <summary> @@ -248,13 +241,17 @@ private void PermuteFactTypeMappings() { + // UNDONE: We should consider whether we can determine what object types will collapse earlier in the process, which would allow us to + // potentially eliminate multiple permutations that have the same result. (Rationale: When an object type is collapsed, it doesn't matter + // whether the mappings away from it are shallow or deep; they both result in the same output.) + int largestChainCount; // Break up the chains of contiguous one-to-one fact types FactTypeChainer chainer = new FactTypeChainer(myPredecidedManyToOneFactTypeMappings, myPredecidedOneToOneFactTypeMappings, myUndecidedOneToOneFactTypeMappings); largestChainCount = chainer.Run(); // Perform one-time pass of top-level types for the decided mappings - PrecalculateDecidedConceptTypes(); + //PrecalculateDecidedConceptTypes(); // This is used in PermuteFactTypeMappings(). We allocate it once, here, for permformance reasons. FactTypeMappingList newlyDecidedFactTypeMappings = new FactTypeMappingList(largestChainCount); @@ -280,7 +277,7 @@ PermuteFactTypeMappings(chain.PossiblePermutations, chain.UndecidedOneToOneFactTypeMappings, newlyDecidedFactTypeMappings, deeplyMappedObjectTypes, 0); EliminateInvalidPermutations(chain); - CalculateTopLevelConceptTypes(chain); + FindSmallestPermutationsInTermsOfConceptTypes(chain); // Add each mapping from the optimal permutation to the "global" set of decided mappings. foreach (FactTypeMapping optimalMapping in ChooseOptimalPermutation(chain).Mappings) @@ -313,166 +310,165 @@ return null; } - private static Permutation ChooseOptimalPermutation(Chain chain) + private static void FindSmallestPermutationsInTermsOfConceptTypes(Chain chain) { - // UNDONE: This should do something smart! - PermutationList smallestPermutationsList = chain.SmallestPermutations; - Permutation firstFinalMappingState = smallestPermutationsList[0]; - smallestPermutationsList.Clear(); - return firstFinalMappingState; - } + int maxPossibleObjectTypes = chain.ObjectTypes.Count; - private void PrecalculateDecidedConceptTypes() - { - // Calculate decided top-level types (these are *not* final until individual permutations have been considered) - foreach (KeyValuePair<FactType, FactTypeMapping> pair in myDecidedFactTypeMappings) - { - ProcessEntity(new ProcessEntityState(pair.Value, null, null, null)); - } - } + // These object types definitely DO result in concept types, but MAY or MAY NOT result in top-level concept types + Dictionary<ObjectType, object> predecidedObjectTypesThatAreIndependentOrSubtypesOrHaveNonPreferredIdentifierMappingsTowards = new Dictionary<ObjectType, object>(maxPossibleObjectTypes); - /// <summary> - /// An object type (A) is a concept type when: - /// 1. It is independent, or - /// 2. It is a subtype, or - /// 3. Another object type (B) is mapped to it, and - /// a. There exists a role being mapped to object type A on which there are no constraints, or - /// b. There exists a role being mapped to object type A on which there is not a preferred uniqueness. - /// - /// A concept type is a top-level concept type when: - /// 1. It is not deeply mapped towards any other concept type. - /// - /// As this method processes the ObjectType passed in it gradually (and probably not in the same pass) executes each of - /// the above checks to see whether the ObjectType is a concept type or top-level concept type. - /// </summary> - /// <param name="state"></param> - private void ProcessEntity(ProcessEntityState state) - { - ObjectType towards = state.Mapping.TowardsObjectType; - if (myInvalidObjectTypes.ContainsKey(towards)) + // These object types definitely DO NOT result in top-level concept types, but MAY or MAY NOT result in concept types + Dictionary<ObjectType, object> predecidedObjectTypesThatHaveDeepMappingsAway = new Dictionary<ObjectType, object>(maxPossibleObjectTypes); + + // By just examining the predecided mappings, we can determine the specified truth values for the following: + // Object Type is Concept Type {true, unknown} + // Object Type is Top Level Concept Type {false, unknown} + + foreach (FactTypeMapping mapping in chain.PredecidedManyToOneFactTypeMappings) { - return; - } - ObjectType from = state.Mapping.FromObjectType; - Role fromRole = state.Mapping.FromRole; - if (from.IsIndependent && !(fromRole is SubtypeMetaRole) && !myPossibleConceptTypes.ContainsKey(from)) - { - // Add the object type as a concept type if it's independent. - myPossibleConceptTypes.Add(from, true); - if (state.ConceptTypeGarbage != null) + Debug.Assert(mapping.MappingDepth == MappingDepth.Shallow); + if (!mapping.IsFromPreferredIdentifier) { - state.ConceptTypeGarbage.Add(from); + predecidedObjectTypesThatAreIndependentOrSubtypesOrHaveNonPreferredIdentifierMappingsTowards[mapping.TowardsObjectType] = null; } } - // If the |from| OT is a primary identifier, DO NOT add the |towards| OT to the top-level list - // (Note that it doesn't mean it cannot be added earlier/later, but will not if only role played is primary identifier) - if (state.Mapping.IsFromPreferredIdentifier) + + foreach (FactTypeMapping mapping in chain.PredecidedOneToOneFactTypeMappings) { - return; - } - if (!myPossibleConceptTypes.ContainsKey(from)) - { - // All top-level concept types are at least concept types - myPossibleConceptTypes.Add(from, true); - if (state.ConceptTypeGarbage != null && !state.ConceptTypeGarbage.Contains(from)) + if (!mapping.IsFromPreferredIdentifier) { - state.ConceptTypeGarbage.Add(from); + predecidedObjectTypesThatAreIndependentOrSubtypesOrHaveNonPreferredIdentifierMappingsTowards[mapping.TowardsObjectType] = null; } - } - MappingDepth mappingType = state.Mapping.MappingDepth; - // If the |from| OT is mapped away deeply, and has objects mapped to it, remove it and invalidate it as a possible top-level type - if (myPossibleTopLevelConceptTypes.ContainsKey(from) && mappingType == MappingDepth.Deep) - { - myPossibleTopLevelConceptTypes.Remove(from); - myInvalidObjectTypes.Add(from, true); - if (state.Restore != null) + if (mapping.FromRole is SubtypeMetaRole) { - state.Restore.Add(from); + predecidedObjectTypesThatAreIndependentOrSubtypesOrHaveNonPreferredIdentifierMappingsTowards[mapping.FromObjectType] = null; } + if (mapping.MappingDepth == MappingDepth.Deep) + { + predecidedObjectTypesThatHaveDeepMappingsAway[mapping.FromObjectType] = null; + } } - // First clause in there because |from| could equal |towards|, and may be invalidated in prior conditional - if (!myInvalidObjectTypes.ContainsKey(towards) && !myPossibleTopLevelConceptTypes.ContainsKey(towards)) + + foreach (ObjectType objectType in chain.ObjectTypes) { - if (state.Garbage != null) + if (objectType.IsAnyIndependent()) { - state.Garbage.Add(towards); + predecidedObjectTypesThatAreIndependentOrSubtypesOrHaveNonPreferredIdentifierMappingsTowards[objectType] = null; } - myPossibleTopLevelConceptTypes.Add(towards, true); } - } - /// <summary> - /// This method processes concept type and top-level concept type conditions gradually as it iterates over the chain, rather than - /// calculating top-level-ness immediately for every concept type. The final state of each concept type is valid after this - /// method is finished executing. - /// - /// See <see cref="ProcessEntity">ProcessEntity</see> for the algorithm. - /// </summary> - /// <param name="chain"></param> - private void CalculateTopLevelConceptTypes(Chain chain) - { - // The smallest overall mapping that we've found - int smallest = int.MaxValue; - // These dictionaries track the OTs that are temporarily removed or added for each permutation in the list - ObjectTypeList garbage = new ObjectTypeList(myDecidedFactTypeMappings.Count); - ObjectTypeList restore = new ObjectTypeList(myDecidedFactTypeMappings.Count); - ObjectTypeList conceptTypeGarbage = new ObjectTypeList(myDecidedFactTypeMappings.Count); - // Now include the permutations in the calculation of top-level types. - for (int i = 0; i < chain.PossiblePermutations.Count; i++) + Dictionary<ObjectType, object> permutationObjectTypesThatHaveNonPreferredIdentifierMappingsTowards = new Dictionary<ObjectType, object>(maxPossibleObjectTypes); + Dictionary<ObjectType, object> permutationObjectTypesThatHaveDeepMappingsAway = new Dictionary<ObjectType, object>(maxPossibleObjectTypes); + + Dictionary<ObjectType, object> notConceptTypes = new Dictionary<ObjectType, object>(maxPossibleObjectTypes); + Dictionary<ObjectType, object> nonTopLevelConceptTypes = new Dictionary<ObjectType, object>(maxPossibleObjectTypes); + Dictionary<ObjectType, object> topLevelConceptTypes = new Dictionary<ObjectType, object>(maxPossibleObjectTypes); + + PermutationList smallestPermutationsInTermsOfConceptTypes = chain.SmallestPermutationsInTermsOfConceptTypes; + + int minTopLevelConceptTypesCount = int.MaxValue; + int minNonTopLevelConceptTypesCount = int.MaxValue; + + foreach (Permutation permutation in chain.PossiblePermutations) { - garbage.Clear(); - restore.Clear(); - Permutation state = chain.PossiblePermutations[i]; - foreach (FactTypeMapping mapping in state.Mappings) + bool isNotOptimalPermutation = false; + + permutationObjectTypesThatHaveDeepMappingsAway.Clear(); + permutationObjectTypesThatHaveNonPreferredIdentifierMappingsTowards.Clear(); + + notConceptTypes.Clear(); + nonTopLevelConceptTypes.Clear(); + topLevelConceptTypes.Clear(); + + foreach (FactTypeMapping mapping in permutation.Mappings) { - ProcessEntityState entitystate = new ProcessEntityState(mapping, restore, garbage, conceptTypeGarbage); - ProcessEntity(entitystate); - if (myPossibleTopLevelConceptTypes.Count > smallest) + if (!mapping.IsFromPreferredIdentifier) { - break; + permutationObjectTypesThatHaveNonPreferredIdentifierMappingsTowards[mapping.TowardsObjectType] = null; } + if (mapping.MappingDepth == MappingDepth.Deep) + { + permutationObjectTypesThatHaveDeepMappingsAway[mapping.FromObjectType] = null; + } } - // Done for this state, so finalize and clean up - state.TopLevelConceptTypes = myPossibleTopLevelConceptTypes.Count; - state.ConceptTypes = myPossibleConceptTypes.Count; - if (state.TopLevelConceptTypes <= smallest) + + foreach (ObjectType objectType in chain.ObjectTypes) { - smallest = state.TopLevelConceptTypes; - PermutationList smallestList = chain.SmallestPermutations; - if (smallestList.Count > 0) + bool isIndependentOrSubtypeOrHasNonPreferredIdentifierMappingsTowards = predecidedObjectTypesThatAreIndependentOrSubtypesOrHaveNonPreferredIdentifierMappingsTowards.ContainsKey(objectType) || + permutationObjectTypesThatHaveNonPreferredIdentifierMappingsTowards.ContainsKey(objectType); + bool hasDeepMappingsAway = predecidedObjectTypesThatHaveDeepMappingsAway.ContainsKey(objectType) || permutationObjectTypesThatHaveDeepMappingsAway.ContainsKey(objectType); + + if (isIndependentOrSubtypeOrHasNonPreferredIdentifierMappingsTowards) { - if (smallestList[0].TopLevelConceptTypes > state.TopLevelConceptTypes) + if (hasDeepMappingsAway) { - smallestList.Clear(); + nonTopLevelConceptTypes[objectType] = null; + if ((topLevelConceptTypes.Count == minTopLevelConceptTypesCount) && (nonTopLevelConceptTypes.Count > minNonTopLevelConceptTypesCount)) + { + // We now have more non-top-level concept types than the minimum, and the same number of top-level concept types as the minimum, so throw this permutation out. + isNotOptimalPermutation = true; + break; + } } - // Be sure the logic works if you put this |else if| into the primary |if|. - else if (smallestList[0].ConceptTypes > state.ConceptTypes) + else { - smallestList.Clear(); + topLevelConceptTypes[objectType] = null; + if (topLevelConceptTypes.Count > minTopLevelConceptTypesCount) + { + // We now have more top-level concept types than the minimum, so throw this permutation out. + isNotOptimalPermutation = true; + break; + } } } - if (smallestList.Count == 0 || smallestList[0].ConceptTypes == state.ConceptTypes) - { - smallestList.Add(state); - } } - // Restore OTs removed from the |myPossibleTopLevelConceptTypes| collection; remove elements that were added to the collection - foreach (ObjectType ot in garbage) + + if (isNotOptimalPermutation) { - myPossibleTopLevelConceptTypes.Remove(ot); + // This isn't an optimal permutation, so go on to the next one. + continue; } - foreach (ObjectType ot in restore) + + Debug.Assert(topLevelConceptTypes.Count <= minTopLevelConceptTypesCount, "Permutations with greater than the minimum number of top-level concept types should have been rejected inline."); + + if (topLevelConceptTypes.Count < minTopLevelConceptTypesCount) { - myPossibleTopLevelConceptTypes.Add(ot, true); - myInvalidObjectTypes.Remove(ot); + // We have a new minimum number of top-level concept types (and hence a new minimum number of non-top-level concept types as well). + minTopLevelConceptTypesCount = topLevelConceptTypes.Count; + minNonTopLevelConceptTypesCount = nonTopLevelConceptTypes.Count; + smallestPermutationsInTermsOfConceptTypes.Clear(); } - foreach (ObjectType ot in conceptTypeGarbage) + else { - myPossibleConceptTypes.Remove(ot); + // We have the same number of top-level concept types as the minimum, so we need to check the number of non-top-level concept types. + if (nonTopLevelConceptTypes.Count > minTopLevelConceptTypesCount) + { + // This isn't an optimal permutation, so go on to the next one. + continue; + } + else if (nonTopLevelConceptTypes.Count < minNonTopLevelConceptTypesCount) + { + // We have a new minimum number of non-top-level concept type. + minNonTopLevelConceptTypesCount = nonTopLevelConceptTypes.Count; + smallestPermutationsInTermsOfConceptTypes.Clear(); + } } + permutation.SetConceptTypes(topLevelConceptTypes, nonTopLevelConceptTypes); + smallestPermutationsInTermsOfConceptTypes.Add(permutation); } } + + + private static Permutation ChooseOptimalPermutation(Chain chain) + { + // UNDONE: This should do something smart! + PermutationList smallestPermutationsInTermsOfConceptTypes = chain.SmallestPermutationsInTermsOfConceptTypes; + Permutation firstFinalMappingState = smallestPermutationsInTermsOfConceptTypes[0]; + //smallestPermutationsInTermsOfConceptTypes.Clear(); + return firstFinalMappingState; + } + /// <summary> /// Returns the maximum number of <see cref="Permutation"/>s that could result for the specified set of undecided <see cref="FactTypeMapping"/>s. /// </summary> @@ -632,4 +628,4 @@ } } #endregion -} +} \ No newline at end of file Modified: trunk/Oial/ORMOialBridge/ORMOialBridgeStructures.cs =================================================================== --- trunk/Oial/ORMOialBridge/ORMOialBridgeStructures.cs 2007-08-30 17:21:57 UTC (rev 1100) +++ trunk/Oial/ORMOialBridge/ORMOialBridgeStructures.cs 2007-08-30 17:24:00 UTC (rev 1101) @@ -55,7 +55,7 @@ } [Serializable] - [DebuggerDisplay("FactTypeMapping (TowardsRole={FactType.RoleCollection.IndexOf(FromRole)}, Depth={MappingDepth}, FactType={FactType.Name})")] + [DebuggerDisplay("FactTypeMapping (TowardsRole={FactType.RoleCollection.IndexOf(TowardsRoleDebug)}, Depth={MappingDepth}, FactType={FactType.Name})")] sealed class FactTypeMapping { private readonly FactType factType; @@ -106,6 +106,14 @@ get { return towardsRole; } } + /// <summary> + /// Used by the <see cref="DebuggerDisplayAttribute"/> for this type. + /// </summary> + private RoleBase TowardsRoleDebug + { + get { return (RoleBase)towardsRole.Proxy ?? towardsRole; } + } + public MappingDepth MappingDepth { get { return mappingDepth; } @@ -251,8 +259,8 @@ sealed class Permutation { private readonly FactTypeMappingList myMappings; - private int myTopLevelConceptTypes; - private int myConceptTypes; + private Dictionary<ObjectType, object> myTopLevelConceptTypes; + private Dictionary<ObjectType, object> myNonTopLevelConceptTypes; public Permutation(FactTypeMappingList mappings) { @@ -264,17 +272,28 @@ get { return myMappings; } } - public int TopLevelConceptTypes + public void SetConceptTypes(Dictionary<ObjectType, object> topLevelConceptTypes, Dictionary<ObjectType, object> nonTopLevelConceptTypes) { - get { return myTopLevelConceptTypes; } - set { myTopLevelConceptTypes = value; } + Debug.Assert(myTopLevelConceptTypes == null && myNonTopLevelConceptTypes == null); + myTopLevelConceptTypes = new Dictionary<ObjectType,object>(topLevelConceptTypes); + myNonTopLevelConceptTypes = new Dictionary<ObjectType,object>(nonTopLevelConceptTypes); } - public int ConceptTypes + public Dictionary<ObjectType, object> TopLevelConceptTypes { - get { return myConceptTypes; } - set { myConceptTypes = value; } + get + { + return myTopLevelConceptTypes; + } } + + public Dictionary<ObjectType, object> NonTopLevelConceptTypes + { + get + { + return myNonTopLevelConceptTypes; + } + } } [Serializable] @@ -302,19 +321,21 @@ [Serializable] sealed class Chain { + private readonly ObjectTypeList myObjectTypes; private readonly FactTypeMappingList myPredecidedManyToOneFactTypeMappings; private readonly FactTypeMappingList myPredecidedOneToOneFactTypeMappings; private readonly FactTypeMappingListList myUndecidedOneToOneFactTypeMappings; private readonly PermutationList myPossiblePermutations; - private readonly PermutationList mySmallestPermutations; + private readonly PermutationList mySmallestPermutationsInTermsOfConceptTypes; public Chain() { + myObjectTypes = new ObjectTypeList(); myPredecidedManyToOneFactTypeMappings = new FactTypeMappingList(); myPredecidedOneToOneFactTypeMappings = new FactTypeMappingList(); myUndecidedOneToOneFactTypeMappings = new FactTypeMappingListList(); myPossiblePermutations = new PermutationList(); - mySmallestPermutations = new PermutationList(); + mySmallestPermutationsInTermsOfConceptTypes = new PermutationList(); } /// <summary> @@ -329,6 +350,18 @@ } /// <summary> + /// The set of all <see cref="ObjectType"/>s that play a role in a one-to-one <see cref="FactType"/> + /// in this <see cref="Chain"/>. + /// </summary> + public ObjectTypeList ObjectTypes + { + get + { + return myObjectTypes; + } + } + + /// <summary> /// Many-to-one FactTypeMappings that are part of this chain but were decided before the permutation phase. /// </summary> public FactTypeMappingList PredecidedManyToOneFactTypeMappings @@ -367,11 +400,11 @@ } /// <summary> - /// The entries from PossiblePermutations which map to the smallest number of top-level concept types. + /// The entries from PossiblePermutations which map to the smallest number of top-level concept types and overall concept types. /// </summary> - public PermutationList SmallestPermutations + public PermutationList SmallestPermutationsInTermsOfConceptTypes { - get { return mySmallestPermutations; } + get { return mySmallestPermutationsInTermsOfConceptTypes; } } } #endregion Modified: trunk/Oial/ORMOialBridge/OialModelIsForORMModel.cs =================================================================== --- trunk/Oial/ORMOialBridge/OialModelIsForORMModel.cs 2007-08-30 17:21:57 UTC (rev 1100) +++ trunk/Oial/ORMOialBridge/OialModelIsForORMModel.cs 2007-08-30 17:24:00 UTC (rev 1101) @@ -466,13 +466,13 @@ /// <param name="undecidedOneToOneFactTypeMappings">The undecided <see cref="FactTypeMapping"/> possibilities.</param> private void FilterFactTypeMappings(FactTypeMappingDictionary decidedManyToOneFactTypeMappings, FactTypeMappingDictionary decidedOneToOneFactTypeMappings, FactTypeMappingListDictionary undecidedOneToOneFactTypeMappings) { - RemoveImpossiblePotentialFactTypeMappings(decidedOneToOneFactTypeMappings, undecidedOneToOneFactTypeMappings); - - int changeCount = 0; + bool changed; do { - changeCount = MapTrivialOneToOneFactTypesWithTwoMandatories(decidedOneToOneFactTypeMappings, undecidedOneToOneFactTypeMappings); - } while (changeCount > 0); + RemoveImpossiblePotentialFactTypeMappings(decidedOneToOneFactTypeMappings, undecidedOneToOneFactTypeMappings); + + changed = MapTrivialOneToOneFactTypesWithTwoMandatories(decidedOneToOneFactTypeMappings, undecidedOneToOneFactTypeMappings) > 0; + } while (changed); } #region Filter Algorithms Methods @@ -484,17 +484,15 @@ /// <param name="undecidedOneToOneFactTypeMappings">The undecided <see cref="FactTypeMapping"/> possibilities.</param> private void RemoveImpossiblePotentialFactTypeMappings(FactTypeMappingDictionary decidedOneToOneFactTypeMappings, FactTypeMappingListDictionary undecidedOneToOneFactTypeMappings) { - ObjectTypeList deeplyMappedObjectTypes = new ObjectTypeList(); + Dictionary<ObjectType, object> deeplyMappedObjectTypes = new Dictionary<ObjectType,object>(decidedOneToOneFactTypeMappings.Count + undecidedOneToOneFactTypeMappings.Count); // For each decided fact type mapping... - foreach (KeyValuePair<FactType, FactTypeMapping> decidedFactTypeMapping in decidedOneToOneFactTypeMappings) + foreach (FactTypeMapping factTypeMapping in decidedOneToOneFactTypeMappings.Values) { - FactTypeMapping factTypeMapping = decidedFactTypeMapping.Value; - // If it's a deep mapping... if (factTypeMapping.MappingDepth == MappingDepth.Deep) { - deeplyMappedObjectTypes.Add(factTypeMapping.FromObjectType); + deeplyMappedObjectTypes[factTypeMapping.FromObjectType] = null; } } @@ -511,13 +509,15 @@ FactTypeMapping potentialFactTypeMapping = potentialFactTypeMappings[i]; // If it is maped away from an ObjectType that is already determined to be mapped elsewhere... - if (deeplyMappedObjectTypes.Contains(potentialFactTypeMapping.FromObjectType) && potentialFactTypeMapping.MappingDepth == MappingDepth.Deep) + 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) { @@ -544,13 +544,12 @@ /// <returns>The number of previously potential one-to-one fact type mappings that are now decided.</returns> private int MapTrivialOneToOneFactTypesWithTwoMandatories(FactTypeMappingDictionary decidedOneToOneFactTypeMappings, FactTypeMappingListDictionary undecidedOneToOneFactTypeMappings) { - int changeCount = 0; - FactTypeList factsPendingDeletion = new FactTypeList(); + FactTypeList factTypesPendingDeletion = new FactTypeList(); - foreach (KeyValuePair<FactType, FactTypeMappingList> undecidedFactTypeMapping in undecidedOneToOneFactTypeMappings) + foreach (KeyValuePair<FactType, FactTypeMappingList> undecidedPair in undecidedOneToOneFactTypeMappings) { - FactType factType = undecidedFactTypeMapping.Key; - FactTypeMappingList potentialFactTypeMappings = undecidedFactTypeMapping.Value; + 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."); @@ -559,48 +558,77 @@ Role secondRole = roles[1].Role; ObjectType firstRolePlayer = firstRole.RolePlayer; ObjectType secondRolePlayer = secondRole.RolePlayer; - bool firstRoleIsMandatory = null != firstRole.SingleRoleAlethicMandatoryConstraint; - bool secondRoleIsMandatory = null != secondRole.SingleRoleAlethicMandatoryConstraint; // If this is a one-to-one fact type with two simple alethic mandatories... - if (firstRoleIsMandatory && secondRoleIsMandatory) + 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: I think we need to be checking that the deep mappings we decide on here are actually in the list of potentials... - // UNDONE: Also, this can create new decided deep mappings, so we need to be applying the related filters after this runs. - - // TODO: This may not be strong enough. - // If secondRolePlayer has no possible deep mappings away from it... + // If secondRolePlayer has no possible deep mappings away from it, and firstRolePlayer does... if (firstRolePlayerHasPossibleDeepMappingsAway && !secondRolePlayerHasPossibleDeepMappingsAway) { - // Deep map toward firstRolePlayer - FactTypeMapping factTypeMapping = new FactTypeMapping(factType, secondRole, firstRole, MappingDepth.Deep); - - decidedOneToOneFactTypeMappings.Add(factType, factTypeMapping); - factsPendingDeletion.Add(factType); - ++changeCount; + // 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); + } + } } - else if (!firstRolePlayerHasPossibleDeepMappingsAway && secondRolePlayerHasPossibleDeepMappingsAway) // ...firstRolePlayer... + // ...and vice-versa... + else if (!firstRolePlayerHasPossibleDeepMappingsAway && secondRolePlayerHasPossibleDeepMappingsAway) { - // Deep map toward secondRolePlayer - FactTypeMapping factTypeMapping = new FactTypeMapping(factType, firstRole, secondRole, MappingDepth.Deep); - - decidedOneToOneFactTypeMappings.Add(factType, factTypeMapping); - factsPendingDeletion.Add(factType); - ++changeCount; + // 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 factsPendingDeletion) + foreach (FactType key in factTypesPendingDeletion) { undecidedOneToOneFactTypeMappings.Remove(key); } - return changeCount; + return factTypesPendingDeletion.Count; } /// <summary> @@ -787,6 +815,16 @@ bool fromRoleIsPreferred = fromRoleUniquenessConstraint.IsPreferred; bool towardsRoleIsPreferred = towardsRoleUniquenessConstraint.IsPreferred; + // UNDONE: Once subtyping is handled correctly on the ORM side, this may need to be adjusted. + // If the from object type doesn't have its own preferred identifier and this is a primary subtyping relationship, mark it as being preferred. + if (!towardsRoleIsPreferred && factTypeIsSubtype && factTypeMapping.FromObjectType.PreferredIdentifier == null) + { + if (((SubtypeFact)factTypeMapping.FactType).IsPrimary) + { + towardsRoleIsPreferred = true; + } + } + RoleAssignment assimilatorConceptType = new RoleAssignment(ConceptTypeAssimilatesConceptType.AssimilatorConceptTypeDomainRoleId, towardsConceptType); RoleAssignment assimilatedConceptType = new RoleAssignment(ConceptTypeAssimilatesConceptType.AssimilatedConceptTypeDomainRoleId, fromConceptType); RoleAssignment[] roleAssignments = { assimilatorConceptType, assimilatedConceptType }; @@ -1071,7 +1109,7 @@ private bool ObjectTypeIsConceptType(ObjectType objectType, FactTypeMappingDictionary factTypeMappings) { // If objectType is independent... - if (objectType.IsIndependent) + if (objectType.IsAnyIndependent()) { return true; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |