public FactTypeMapping(FactType factType, Role fromRole, Role towardsRole, FactTypeMappingFlags flags) { myFactType = factType; myFromRole = fromRole; myTowardsRole = towardsRole; myFromObjectType = fromRole.RolePlayer; myTowardsObjectType = towardsRole.RolePlayer; if (0 == (flags & FactTypeMappingFlags.FromPreferredIdentifier) && DetermineWhetherFromIsPreferredIdentifier()) { flags |= FactTypeMappingFlags.FromPreferredIdentifier; } myFlags = flags; }
/// <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; } } } }