private static void ValidateReferenceModeNamingChanged(ReferenceModeNamingCustomizesObjectType referenceModeNamingCustomizesObjectType) { if (null != referenceModeNamingCustomizesObjectType) { ORMCore.ObjectType objectType = referenceModeNamingCustomizesObjectType.ObjectType; if (objectType != null) { ConceptType conceptType = ConceptTypeIsForObjectType.GetConceptType(objectType); if (null == conceptType) { foreach (ORMCore.Role role in objectType.PlayedRoleCollection) { foreach (ConceptTypeChild conceptTypeChild in ConceptTypeChildHasPathFactType.GetConceptTypeChild(role.FactType)) { ValidateConceptTypeChildNameChanged(conceptTypeChild); } } } else { ValidateConceptTypeNameChanged(conceptType); } } } }
/// <summary> /// for regular relationships /// </summary> /// <param name="relation"></param> /// <param name="source"></param> /// <param name="target"></param> /// <param name="notifyAdded"></param> /// <param name="associationCounter"></param> /// <returns></returns> private static bool CreateBinaryAssociation(ConceptTypeChild relation, ConceptType source, ConceptType target, INotifyElementAdded notifyAdded, ref int associationCounter) { if (BinaryAssociationHasConceptTypeChild.GetBinaryAssociation(relation).Count > 0) { //it has already been created return(true); } else if (EntityTypeIsPrimarilyForConceptType.GetEntityType(target) != null) { #region create association BinaryAssociation b = new BinaryAssociation(relation.Store, new PropertyAssignment[] { new PropertyAssignment(BinaryAssociation.NumberDomainPropertyId, associationCounter++) }); //new BinaryAssociationHasConceptTypeChild(b, relation); BinaryAssociationHasConceptTypeChild.GetConceptTypeChildPath(b).Add(relation); Role r1 = new Role(relation.Store, new PropertyAssignment[] { new PropertyAssignment(Role.PredicateTextDomainPropertyId, source.Name) }); Role r2 = new Role(relation.Store, new PropertyAssignment[] { new PropertyAssignment(Role.PredicateTextDomainPropertyId, target.Name) }); b.RoleCollection.Add(r1); b.RoleCollection.Add(r2); EntityType sourceEntity = EntityTypeIsPrimarilyForConceptType.GetEntityType(source); EntityType targetEntity = EntityTypeIsPrimarilyForConceptType.GetEntityType(target); sourceEntity.RoleCollection.Add(r1); targetEntity.RoleCollection.Add(r2); sourceEntity.BarkerErModel.BinaryAssociationCollection.Add(b); #endregion //determine whether roles are mandatory or optional List <ConceptTypeChild> links = new List <ConceptTypeChild>(1); links.Add(relation); r1.IsMandatory = AllStepsMandatory(targetEntity, links); if (relation is ConceptTypeAssimilatesConceptType) { r2.IsMandatory = AllStepsMandatory(sourceEntity, links); } #region determine whether roles are multivalued or not - and possibly rename ORMCore.ObjectType sourceObjectType = ConceptTypeIsForObjectType.GetObjectType(source); ORMCore.ObjectType targetObjectType = ConceptTypeIsForObjectType.GetObjectType(target); ORMCore.UniquenessConstraint uSource = null, uTarget = null; foreach (ORMCore.FactType factType in ConceptTypeChildHasPathFactType.GetPathFactTypeCollection(relation)) { Debug.Assert(factType.RoleCollection.Count == 2, "Error when mapping to Barker ER; the fact type is not binary"); foreach (ORMCore.RoleBase r in factType.RoleCollection) { //need to use RoleBase because we might run into RoleProxy ORMCore.Role role = r.Role; foreach (ORMCore.ConstraintRoleSequence constraintRoleSequence in role.ConstraintRoleSequenceCollection) { ORMCore.UniquenessConstraint uninquenessConstraint = constraintRoleSequence as ORMCore.UniquenessConstraint; if (uninquenessConstraint != null && //check that it's a uniqueness constraint uninquenessConstraint.Modality == ORMCore.ConstraintModality.Alethic && //check it's alethic uninquenessConstraint.IsInternal) //check it's internal { if (role.RolePlayer == sourceObjectType) { uSource = uninquenessConstraint; } if (role.RolePlayer == targetObjectType) { uTarget = uninquenessConstraint; } } } } //name the roles properly //TODO this is a hack; proper name generation is yet to be implemented foreach (ORMCore.ReadingOrder order in factType.ReadingOrderCollection) { string text = order.ReadingText; int first = text.IndexOf('}') + 1; text = text.Substring(first, text.LastIndexOf('{') - first); text = text.Trim(); if (!string.IsNullOrEmpty(text) && order.RoleCollection != null && order.RoleCollection.Count > 0 && order.RoleCollection[0].Role != null) { ORMCore.ObjectType o = order.RoleCollection[0].Role.RolePlayer; if (o == sourceObjectType) { r1.PredicateText = text; } else if (o == targetObjectType) { r2.PredicateText = text; } } } } if (uSource != null && uSource == uTarget) { //it's many-to-many r1.IsMultiValued = true; r2.IsMultiValued = true; } else if (uSource == null || uTarget == null) { //it's one-to-many r1.IsMultiValued = uSource != null; r2.IsMultiValued = uTarget != null; } else if (uSource != null && uTarget != null) { //it's one-to-one r1.IsMultiValued = false; r2.IsMultiValued = false; } else { Debug.Fail("Found a fact type with no uniqueness constraints!"); } #endregion #region primary id? foreach (Uniqueness u in UniquenessIncludesConceptTypeChild.GetUniquenessCollection(relation)) { if (u.IsPreferred) { r1.IsPrimaryIdComponent = true; break; } } #endregion //notify elements added if (notifyAdded != null) { notifyAdded.ElementAdded(b, true); notifyAdded.ElementAdded(r1, true); notifyAdded.ElementAdded(r2, true); } return(true); } else { //should not create binary association in this case return(false); } }
/// <summary> /// Check if two data types can be compared. This is a weaker check /// than <see cref="IsAssignableValueType"/> in that it does not /// do any facet checking to see if one value can store the only, /// but only checks if the two can be compared. /// </summary> /// <param name="valueType1">The first value type to compare.</param> /// <param name="valueType2">The second value type to compare.</param> /// <param name="equalityOnly">Set to true if the equality or inequality /// of the two values is required, but an ordered check is not.</param> /// <returns><see langword="true"/> if the two types can be compared.</returns> public static bool IsComparableValueType(ObjectType valueType1, ObjectType valueType2, bool equalityOnly) { DataType dataType1 = valueType1.DataType; DataType dataType2 = valueType2.DataType; if (dataType1 == dataType2) { switch (dataType1.PortableDataType) { case PortableDataType.Unspecified: // Give the user the benefit of the doubt that fixing the // unspecified data type will result in comparable values. return(true); 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. return(valueType1 == valueType2); default: return(dataType1.CanCompare && (equalityOnly || (dataType1.RangeSupport != DataTypeRangeSupport.None))); } } else if (dataType1.CanCompare && dataType2.CanCompare && (equalityOnly || (dataType1.RangeSupport != DataTypeRangeSupport.None && dataType2.RangeSupport != DataTypeRangeSupport.None))) { // Look at specific types. PortableDataType targetType = dataType1.PortableDataType; PortableDataType sourceType = dataType2.PortableDataType; if (sourceType == PortableDataType.Unspecified) { // Give user the benefit of the doubt that the types will be made comparable // if this choice is made. return(true); } 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: return(true); } break; case PortableDataType.NumericSignedInteger: case PortableDataType.NumericSignedSmallInteger: case PortableDataType.NumericSignedLargeInteger: case PortableDataType.NumericUnsignedInteger: case PortableDataType.NumericUnsignedTinyInteger: case PortableDataType.NumericUnsignedSmallInteger: case PortableDataType.NumericUnsignedLargeInteger: case PortableDataType.NumericFloatingPoint: case PortableDataType.NumericSinglePrecisionFloatingPoint: case PortableDataType.NumericDoublePrecisionFloatingPoint: case PortableDataType.NumericDecimal: case PortableDataType.NumericMoney: switch (sourceType) { case PortableDataType.NumericSignedInteger: case PortableDataType.NumericSignedSmallInteger: case PortableDataType.NumericSignedLargeInteger: case PortableDataType.NumericUnsignedInteger: case PortableDataType.NumericUnsignedTinyInteger: case PortableDataType.NumericUnsignedSmallInteger: case PortableDataType.NumericUnsignedLargeInteger: case PortableDataType.NumericFloatingPoint: case PortableDataType.NumericSinglePrecisionFloatingPoint: case PortableDataType.NumericDoublePrecisionFloatingPoint: case PortableDataType.NumericDecimal: case PortableDataType.NumericMoney: return(true); } break; //case PortableDataType.RawDataFixedLength: //case PortableDataType.RawDataVariableLength: //case PortableDataType.RawDataLargeLength: //case PortableDataType.RawDataPicture: //case PortableDataType.RawDataOleObject: // Raw data types are not comparable, these cases would form a dead code path. //case PortableDataType.NumericAutoCounter: //case PortableDataType.TemporalTime: //case PortableDataType.TemporalDate: //case PortableDataType.OtherRowId: //case PortableDataType.OtherObjectId: // These compare only to themselves, will be caught in first if block case PortableDataType.TemporalAutoTimestamp: case PortableDataType.TemporalDateAndTime: switch (sourceType) { case PortableDataType.TemporalAutoTimestamp: 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> /// Binarizes the unary <see cref="FactType"/> specified by <paramref name="unaryFactType"/>, defaulting /// to using open-world assumption. The caller is responsible for making sure <paramref name="unaryFactType"/> /// is in fact a unary fact type. /// </summary> public static void BinarizeUnary(FactType unaryFactType, INotifyElementAdded notifyAdded) { Partition partition = unaryFactType.Partition; Store store = partition.Store; IHasAlternateOwner <FactType> toAlternateOwner; IAlternateElementOwner <FactType> alternateFactTypeOwner = (null == (toAlternateOwner = unaryFactType as IHasAlternateOwner <FactType>)) ? null : toAlternateOwner.AlternateOwner; LinkedElementCollection <RoleBase> roleCollection = unaryFactType.RoleCollection; Debug.Assert(roleCollection.Count == 1, "Unaries should only have one role."); Role unaryRole = (Role)roleCollection[0]; string implicitBooleanValueTypeName = GetImplicitBooleanValueTypeName(unaryRole); // UNDONE: We are using open-world assumption now // Setup the mandatory constraint (for closed-world assumption) //MandatoryConstraint mandatoryConstraint = MandatoryConstraint.CreateSimpleMandatoryConstraint(unaryRole); //mandatoryConstraint.Model = unaryFactType.Model; //if (notifyAdded != null) //{ // notifyAdded.ElementAdded(mandatoryConstraint, true); //} // Setup the uniqueness constraint (to make the newly binarized FactType valid) if (unaryRole.SingleRoleAlethicUniquenessConstraint == null) { UniquenessConstraint uniquenessConstraint = UniquenessConstraint.CreateInternalUniquenessConstraint(unaryFactType); uniquenessConstraint.RoleCollection.Add(unaryRole); if (notifyAdded != null) { notifyAdded.ElementAdded(uniquenessConstraint, true); } } // Setup the boolean role (to make the FactType a binary) Role implicitBooleanRole = new Role(partition, null); implicitBooleanRole.Name = unaryRole.Name; // Setup the boolean value type (because the boolean role needs a role player) IAlternateElementOwner <ObjectType> alternateObjectTypeOwner = null; DomainClassInfo alternateCtor = (null != alternateFactTypeOwner && null != (alternateObjectTypeOwner = alternateFactTypeOwner as IAlternateElementOwner <ObjectType>)) ? alternateObjectTypeOwner.GetOwnedElementClassInfo(typeof(ObjectType)) : null; PropertyAssignment implicitBooleanProperty = new PropertyAssignment(ObjectType.IsImplicitBooleanValueDomainPropertyId, true); ObjectType implicitBooleanValueType = (alternateCtor != null) ? (ObjectType)partition.ElementFactory.CreateElement(alternateCtor, implicitBooleanProperty) : new ObjectType(partition, implicitBooleanProperty); Dictionary <object, object> contextInfo = store.TransactionManager.CurrentTransaction.TopLevelTransaction.Context.ContextInfo; object duplicateNamesKey = ORMModel.AllowDuplicateNamesKey; bool removeDuplicateNamesKey = false; object duplicateSignaturesKey = ORMModel.BlockDuplicateReadingSignaturesKey; bool addDuplicateSignaturesKey = false; try { if (!contextInfo.ContainsKey(duplicateNamesKey)) { contextInfo[duplicateNamesKey] = null; removeDuplicateNamesKey = true; } if (contextInfo.ContainsKey(duplicateSignaturesKey)) { contextInfo[duplicateSignaturesKey] = null; addDuplicateSignaturesKey = true; } implicitBooleanValueType.Name = implicitBooleanValueTypeName; if (alternateCtor != null) { ((IHasAlternateOwner <ObjectType>)implicitBooleanValueType).AlternateOwner = alternateObjectTypeOwner; } else { implicitBooleanValueType.Model = unaryFactType.ResolvedModel; } if (notifyAdded != null) { notifyAdded.ElementAdded(implicitBooleanValueType, true); } } finally { if (removeDuplicateNamesKey) { contextInfo.Remove(duplicateNamesKey); } if (addDuplicateSignaturesKey) { contextInfo[duplicateSignaturesKey] = null; } } implicitBooleanValueType.DataType = store.ElementDirectory.FindElements <TrueOrFalseLogicalDataType>(false)[0]; // Set value constraint on implicit boolean ValueType for open-world assumption ValueTypeValueConstraint implicitBooleanValueConstraint = implicitBooleanValueType.ValueConstraint = new ValueTypeValueConstraint(partition, null); // Add the true-only ValueRange to the value constraint for open-world assumption implicitBooleanValueConstraint.ValueRangeCollection.Add(new ValueRange(partition, new PropertyAssignment(ValueRange.MinValueDomainPropertyId, bool.TrueString), new PropertyAssignment(ValueRange.MaxValueDomainPropertyId, bool.TrueString))); // Make the boolean value type the role player for the implicit boolean role implicitBooleanRole.RolePlayer = implicitBooleanValueType; // Add the boolean role to the FactType roleCollection.Add(implicitBooleanRole); if (notifyAdded != null) { notifyAdded.ElementAdded(implicitBooleanRole, true); } }
/// <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); }