/// <summary> /// AddRule: typeof(ORMSolutions.ORMArchitect.Core.ObjectModel.ValueTypeHasDataType) /// </summary> private static void DataTypeAddedRule(ElementAddedEventArgs e) { ValueTypeHasDataType link = (ValueTypeHasDataType)e.ModelElement; if (link.DataType is AutoCounterNumericDataType) { SignificantObjectTypeChange(link.ValueType); } }
/// <summary> /// DeleteRule: typeof(ORMSolutions.ORMArchitect.Core.ObjectModel.ValueTypeHasDataType) /// </summary> private static void DataTypeDeletedRule(ElementDeletedEventArgs e) { ValueTypeHasDataType link = (ValueTypeHasDataType)e.ModelElement; ObjectType objectType; if (link.DataType is AutoCounterNumericDataType && !(objectType = link.ValueType).IsDeleted) { SignificantObjectTypeChange(objectType); } }
private static void UpdateTablesOnDataTypeChange(ValueTypeHasDataType link) { InformationTypeFormat format; LinkedElementCollection <ConceptType> conceptTypes; if (null != (format = InformationTypeFormatIsForValueType.GetInformationTypeFormat(link.ValueType)) && 0 != (conceptTypes = InformationType.GetConceptTypeCollection(format)).Count) { foreach (ConceptType conceptType in conceptTypes) { UpdateTablesForConceptType(conceptType, null, null); } } }
/// <summary> /// AddRule: typeof(ValueTypeHasDataType) /// Stop the ValueTypeHasDataType relationship from being /// added if an ObjectType participates in a subtyping relationship /// </summary> private static void EnsureConsistentDataTypesAddRule(ElementAddedEventArgs e) { ValueTypeHasDataType link = e.ModelElement as ValueTypeHasDataType; ObjectType objectType = link.ValueType; LinkedElementCollection <Role> playedRoles = objectType.PlayedRoleCollection; int playedRoleCount = playedRoles.Count; for (int i = 0; i < playedRoleCount; ++i) { Role testRole = playedRoles[i]; if (testRole is SubtypeMetaRole || testRole is SupertypeMetaRole) { if (null != testRole.FactType) { ThrowMixedRolePlayerTypesException(); } } } }
private static void UpdateTablesOnDataTypeChange(ValueTypeHasDataType link) { InformationTypeFormat format; LinkedElementCollection<ConceptType> conceptTypes; if (null != (format = InformationTypeFormatIsForValueType.GetInformationTypeFormat(link.ValueType)) && 0 != (conceptTypes = InformationType.GetConceptTypeCollection(format)).Count) { foreach (ConceptType conceptType in conceptTypes) { UpdateTablesForConceptType(conceptType, null, null); } } }
/// <summary> /// Test if an instance of one value type can be always be assigned to /// an instance of another value type. /// </summary> /// <param name="targetValueType">The type of the value being assigned to.</param> /// <param name="sourceValueType">The type of the value being assigned from.</param> /// <returns><see langword="true"/> if the source value can be assigned to the target value.</returns> /// <remarks>If either data type is unspecified, then the assumption is made that there is an error /// for this condition elsewhere and that the user will fix it, so this method returns true in these /// cases. Autogenerated values are assumed to be incompatible if they come from different value types /// because assigning autogenerated values to each other is also meaningingless.</remarks> public static bool IsAssignableValueType(ObjectType targetValueType, ObjectType sourceValueType) { if (targetValueType == sourceValueType) { return(true); } ValueTypeHasDataType targetUse; ValueTypeHasDataType sourceUse; if (null == (targetUse = ValueTypeHasDataType.GetLinkToDataType(targetValueType)) || null == (sourceUse = ValueTypeHasDataType.GetLinkToDataType(sourceValueType))) { return(false); } PortableDataType targetType = targetUse.DataType.PortableDataType; PortableDataType sourceType = sourceUse.DataType.PortableDataType; if (sourceType == PortableDataType.Unspecified) { // Give user the benefit of the doubt that the types will be made compatible // if this choice is made. return(true); } int targetLength; int sourceLength; int targetScale; int sourceScale; switch (targetType) { case PortableDataType.Unspecified: // Let user fix return(true); case PortableDataType.TextFixedLength: case PortableDataType.TextVariableLength: case PortableDataType.TextLargeLength: switch (sourceType) { case PortableDataType.TextFixedLength: case PortableDataType.TextVariableLength: case PortableDataType.TextLargeLength: targetLength = targetUse.Length; sourceLength = sourceUse.Length; return((targetLength == 0 ? int.MaxValue : targetLength) >= (sourceLength == 0 ? int.MaxValue : sourceLength)); } break; case PortableDataType.NumericSignedInteger: switch (sourceType) { case PortableDataType.NumericSignedInteger: case PortableDataType.NumericSignedSmallInteger: return(true); case PortableDataType.NumericDecimal: if (sourceUse.Scale == 0) { sourceLength = sourceUse.Length; if (sourceLength != 0 && sourceLength <= 9) // 10 might be too big { return(true); } } break; } break; case PortableDataType.NumericSignedSmallInteger: switch (sourceType) { case PortableDataType.NumericSignedSmallInteger: return(true); case PortableDataType.NumericDecimal: if (sourceUse.Scale == 0) { sourceLength = sourceUse.Length; if (sourceLength != 0 && sourceLength <= 4) // 5 might be too big { return(true); } } break; } break; case PortableDataType.NumericSignedLargeInteger: switch (sourceType) { case PortableDataType.NumericSignedInteger: case PortableDataType.NumericSignedSmallInteger: case PortableDataType.NumericSignedLargeInteger: return(true); case PortableDataType.NumericDecimal: if (sourceUse.Scale == 0) { sourceLength = sourceUse.Length; if (sourceLength != 0 && sourceLength <= 18) // 19 might be too big { return(true); } } break; } break; case PortableDataType.NumericUnsignedInteger: switch (sourceType) { case PortableDataType.NumericUnsignedInteger: case PortableDataType.NumericUnsignedTinyInteger: case PortableDataType.NumericUnsignedSmallInteger: return(true); } break; case PortableDataType.NumericUnsignedTinyInteger: switch (sourceType) { case PortableDataType.NumericUnsignedTinyInteger: return(true); } break; case PortableDataType.NumericUnsignedSmallInteger: switch (sourceType) { case PortableDataType.NumericUnsignedTinyInteger: case PortableDataType.NumericUnsignedSmallInteger: return(true); } break; case PortableDataType.NumericUnsignedLargeInteger: switch (sourceType) { case PortableDataType.NumericUnsignedInteger: case PortableDataType.NumericUnsignedTinyInteger: case PortableDataType.NumericUnsignedSmallInteger: case PortableDataType.NumericUnsignedLargeInteger: return(true); } break; //case PortableDataType.NumericAutoCounter: // Only support this if the value types are the same. Otherwise, we're mapping different // counters to each other, which is meaningless. case PortableDataType.NumericFloatingPoint: case PortableDataType.NumericSinglePrecisionFloatingPoint: case PortableDataType.NumericDoublePrecisionFloatingPoint: switch (sourceType) { case PortableDataType.NumericFloatingPoint: sourceLength = sourceUse.Length; if (sourceLength == 0) { sourceLength = 53; } break; case PortableDataType.NumericSinglePrecisionFloatingPoint: sourceLength = 24; break; case PortableDataType.NumericDoublePrecisionFloatingPoint: sourceLength = 53; break; default: sourceLength = -1; break; } if (sourceLength != -1) { switch (targetType) { case PortableDataType.NumericSinglePrecisionFloatingPoint: targetLength = 24; break; case PortableDataType.NumericDoublePrecisionFloatingPoint: targetLength = 53; break; //case PortableDataType.NumericFloatingPoint: default: targetLength = targetUse.Length; if (targetLength == 0) { targetLength = 53; } break; } if (targetLength >= sourceLength) { return(true); } } break; case PortableDataType.NumericDecimal: case PortableDataType.NumericMoney: sourceScale = 0; switch (sourceType) { case PortableDataType.NumericDecimal: sourceLength = sourceUse.Length; if (sourceLength == 0) { sourceLength = 18; } else { sourceScale = sourceUse.Scale; } break; case PortableDataType.NumericMoney: sourceLength = 19; sourceScale = 4; break; case PortableDataType.NumericSignedInteger: case PortableDataType.NumericUnsignedInteger: sourceLength = 10; break; case PortableDataType.NumericSignedSmallInteger: case PortableDataType.NumericUnsignedSmallInteger: sourceLength = 5; break; case PortableDataType.NumericSignedLargeInteger: sourceLength = 19; break; case PortableDataType.NumericUnsignedLargeInteger: sourceLength = 20; break; case PortableDataType.NumericUnsignedTinyInteger: sourceLength = 3; break; default: sourceLength = -1; break; } if (sourceLength != -1) { if (targetType == PortableDataType.NumericMoney) { targetLength = 19; targetScale = 4; } else { targetLength = targetUse.Length; // Length maps to precision, verify precision first, then scale if (targetLength == 0) { targetLength = 18; targetScale = 0; } else { targetScale = targetUse.Scale; } } if (targetLength >= sourceLength && targetScale >= sourceScale) { return(true); } } break; case PortableDataType.RawDataFixedLength: case PortableDataType.RawDataVariableLength: case PortableDataType.RawDataLargeLength: switch (sourceType) { case PortableDataType.RawDataFixedLength: case PortableDataType.RawDataVariableLength: case PortableDataType.RawDataLargeLength: targetLength = targetUse.Length; sourceLength = sourceUse.Length; return((targetLength == 0 ? int.MaxValue : targetLength) >= (sourceLength == 0 ? int.MaxValue : sourceLength)); } break; case PortableDataType.RawDataPicture: case PortableDataType.RawDataOleObject: case PortableDataType.TemporalTime: case PortableDataType.TemporalDate: case PortableDataType.OtherRowId: case PortableDataType.OtherObjectId: if (sourceType == targetType) { return(true); } break; case PortableDataType.TemporalAutoTimestamp: case PortableDataType.TemporalDateAndTime: switch (sourceType) { case PortableDataType.TemporalAutoTimestamp: case PortableDataType.TemporalTime: case PortableDataType.TemporalDate: case PortableDataType.TemporalDateAndTime: return(true); } break; case PortableDataType.LogicalTrueOrFalse: case PortableDataType.LogicalYesOrNo: switch (sourceType) { case PortableDataType.LogicalTrueOrFalse: case PortableDataType.LogicalYesOrNo: return(true); } break; } return(false); }
/// <summary> /// Helper method to recursively walk value roles. A value role /// is any role that is allowed to have a value constraint. /// </summary> /// <param name="playedRoles">Roles from an ObjectType to walk. The assumption is made that the /// owning ObjectType is either a value type or has a preferred identifier with exactly one role</param> /// <param name="dataTypeLink">The data type information for the constraint</param> /// <param name="pathRoots">The <see cref="RolePathObjectTypeRoot"/> relationships from a role path associated /// with the root path.</param> /// <param name="previousValueConstraint">The value constraint nearest this value role. /// Any value constraint on the current set of roles must be a subset of the previousValueConstraint.</param> /// <param name="skipRole">A role to skip. If the playedRoles came from a preferred identifier, /// then the skipRole is the opposite role.</param> /// <param name="walkSubtypes">true to walk subtypes. Should be true if the playedRoles come from an /// EntityType and false if they come from a ValueType</param> /// <param name="visitor">The callback delegate</param> /// <returns>true to continue iteration</returns> private static bool WalkDescendedValueRoles(IList<Role> playedRoles, IList<RolePathObjectTypeRoot> pathRoots, ValueTypeHasDataType dataTypeLink, ValueConstraint previousValueConstraint, Role skipRole, bool walkSubtypes, ValueRoleVisitor visitor) { int count = pathRoots.Count; for (int i = 0; i < count; ++i) { RolePathObjectTypeRoot pathRoot = pathRoots[i]; if (!visitor(null, null, pathRoot, dataTypeLink, pathRoot.ValueConstraint, previousValueConstraint)) { return false; } } count = playedRoles.Count; for (int i = 0; i < count; ++i) { Role role = playedRoles[i]; SupertypeMetaRole supertypeRole; if (role == skipRole) { // Nothing to do } else if (null != (supertypeRole = role as SupertypeMetaRole)) { if (walkSubtypes) { SubtypeFact subtypeFact = (SubtypeFact)role.FactType; ObjectType subtype; if (subtypeFact.ProvidesPreferredIdentifier && null != (subtype = subtypeFact.Subtype) && subtype.PreferredIdentifier == null) { if (!WalkDescendedValueRoles(subtype.PlayedRoleCollection, RolePathObjectTypeRoot.GetLinksToRolePathCollection(subtype), dataTypeLink, previousValueConstraint, null, true, visitor)) { return false; } } } } else if (!(role is SubtypeMetaRole)) { RoleValueConstraint currentValueConstraint = role.ValueConstraint; if (!visitor(role, null, null, dataTypeLink, currentValueConstraint, previousValueConstraint)) { return false; } if (currentValueConstraint != null && !currentValueConstraint.IsDeleted) { previousValueConstraint = currentValueConstraint; } foreach (PathedRole pathedRole in PathedRole.GetLinksToRolePathCollection(role)) { // UNDONE: VALUEROLE This does not correctly report a value constraint from a previous // path node. Note that this, as well as allowing value restrictions on supertype roles // (and possibly other patterns), can result in multiple previous value constraints, so // the callback signature may possibly need to be modified here. As of changeset 1442, // none of the callbacks use the previousValueConstraint information, so we can ignore // this for now. // Note that we visit for the pathed role even if no value constraint is present // to allow processing for this pathed role. if (!visitor(role, pathedRole, null, dataTypeLink, pathedRole.ValueConstraint, previousValueConstraint)) { return false; } } // Walk sequences to find a single-role preferred identifier so // we can get to the next link. LinkedElementCollection<ConstraintRoleSequence> sequences = role.ConstraintRoleSequenceCollection; int sequencesCount = sequences.Count; for (int j = 0; j < sequencesCount; ++j) { UniquenessConstraint constraint = sequences[j] as UniquenessConstraint; ObjectType identifierFor; if (null != (constraint = sequences[j] as UniquenessConstraint) && null != (identifierFor = constraint.PreferredIdentifierFor) && constraint.RoleCollection.Count == 1) { RoleBase nextSkipRole = role.OppositeRoleAlwaysResolveProxy; if (nextSkipRole == null) { return false; } if (!WalkDescendedValueRoles(identifierFor.PlayedRoleCollection, RolePathObjectTypeRoot.GetLinksToRolePathCollection(identifierFor), dataTypeLink, previousValueConstraint, nextSkipRole.Role, true, visitor)) { return false; } } } } } return true; }