/// <summary> /// Display a formatted string defining the relationship /// for the component name. /// </summary> public override string GetComponentName() { SubtypeFact subtypeFact = ModelElement; ObjectType subtype; ObjectType supertype; if ((subtype = subtypeFact.Subtype) != null && (supertype = subtypeFact.Supertype) != null) { return(string.Format(CultureInfo.InvariantCulture, ResourceStrings.SubtypeFactComponentNameFormat, TypeDescriptor.GetComponentName(subtype), TypeDescriptor.GetComponentName(supertype))); } return(base.GetComponentName()); }
/// <summary> /// Create a connection between an ExternalConstraintShape and a FactType. Roles /// used in the connection are stored with the currently active connect action. /// </summary> /// <param name="sourceShapeElement">The source of the requested connection</param> /// <param name="targetShapeElement">The target of the requested connection</param> /// <param name="paintFeedbackArgs">PaintFeedbackArgs</param> public override void CreateConnection(ShapeElement sourceShapeElement, ShapeElement targetShapeElement, PaintFeedbackArgs paintFeedbackArgs) { SubtypeConnectAction action = (sourceShapeElement.Diagram as ORMDiagram).SubtypeConnectAction; ObjectType sourceObjectType; ObjectType targetObjectType; if ((null != (sourceObjectType = action.mySourceObjectType)) && (null != (targetObjectType = ObjectTypeFromShape(targetShapeElement)))) { SubtypeFact.Create(sourceObjectType, targetObjectType); } }
/// <summary> /// Implements <see cref="IReconfigureableLink.Reconfigure"/> /// </summary> protected void Reconfigure(ShapeElement discludedShape) { SubtypeFact subtypeFact = AssociatedSubtypeFact; ObjectType subType = subtypeFact.Subtype; ObjectType superType = subtypeFact.Supertype; if (subType != null && superType != null) { FactType nestedSubFact = subType.NestedFactType; FactType nestedSuperFact = superType.NestedFactType; MultiShapeUtility.ReconfigureLink(this, (nestedSubFact == null) ? subType as ModelElement : nestedSubFact as ModelElement, (nestedSuperFact == null) ? superType as ModelElement : nestedSuperFact as ModelElement, discludedShape); } }
public void Test5(Store store) { myTestServices.Compare(store, (MethodInfo)MethodInfo.GetCurrentMethod(), "FullyAbsorbed"); myTestServices.LogMessage("Separate a one-to-main objectification"); ORMModel model = store.ElementDirectory.FindElements <ORMModel>()[0]; ObjectType birthObjectType = (ObjectType)model.ObjectTypesDictionary.GetElement("Birth").FirstElement; FactType factTypeToSeparate = birthObjectType.PreferredIdentifier.RoleCollection[0].Proxy.FactType; MappingCustomizationModel customizationModel; using (Transaction t = store.TransactionManager.BeginTransaction("Separate assimilated objectification")) { customizationModel = new MappingCustomizationModel(store); AssimilationMapping mapping = new AssimilationMapping(store, new PropertyAssignment(AssimilationMapping.AbsorptionChoiceDomainPropertyId, AssimilationAbsorptionChoice.Separate)); new AssimilationMappingCustomizesFactType(mapping, factTypeToSeparate); mapping.Model = customizationModel; t.Commit(); } myTestServices.Compare(store, (MethodInfo)MethodInfo.GetCurrentMethod(), "SeparateObjectification"); myTestServices.LogMessage("Add a longer assimilation chain with a separate end point"); ObjectType partyObjectType = (ObjectType)model.ObjectTypesDictionary.GetElement("Party").FirstElement; AssimilationMapping partyIsThingAssimilationMapping; using (Transaction t = store.TransactionManager.BeginTransaction("Longer assimilation chain")) { partyObjectType.ReferenceModeDisplay = ""; // Using ReferenceModeDisplay instead of ReferenceModeString to automatically kill Party_id ObjectType thingObjectType = new ObjectType(store, new PropertyAssignment(ObjectType.NameDomainPropertyId, "Thing"), new PropertyAssignment(ObjectType.IsIndependentDomainPropertyId, true)); thingObjectType.Model = model; thingObjectType.ReferenceModeString = "id"; SubtypeFact partyIsThingSubtypeFact = SubtypeFact.Create(partyObjectType, thingObjectType); partyIsThingAssimilationMapping = new AssimilationMapping(store, new PropertyAssignment(AssimilationMapping.AbsorptionChoiceDomainPropertyId, AssimilationAbsorptionChoice.Separate)); new AssimilationMappingCustomizesFactType(partyIsThingAssimilationMapping, partyIsThingSubtypeFact); partyIsThingAssimilationMapping.Model = customizationModel; t.Commit(); } myTestServices.Compare(store, (MethodInfo)MethodInfo.GetCurrentMethod(), "SeparateRemoteSupertype"); myTestServices.LogMessage("Remove the remote separation"); using (Transaction t = store.TransactionManager.BeginTransaction("")) { partyIsThingAssimilationMapping.AbsorptionChoice = AssimilationAbsorptionChoice.Absorb; t.Commit(); } }
/// <summary> /// Ensure that the <see cref="SubtypeFact.ProvidesPreferredIdentifier"/> property is read-only when /// it is <see langword="true"/>. /// </summary> protected override bool IsPropertyDescriptorReadOnly(ElementPropertyDescriptor propertyDescriptor) { if (propertyDescriptor.DomainPropertyInfo.Id.Equals(SubtypeFact.ProvidesPreferredIdentifierDomainPropertyId)) { SubtypeFact subtypeFact = ModelElement; ObjectType subtype = subtypeFact.Subtype; if (subtypeFact.ProvidesPreferredIdentifier) { // We can only turn this off if there is a single candidate // internal uniqueness constraint on an objectification that // can automatically take the preferred identifier FactType objectifiedFactType; if (null != (objectifiedFactType = subtype.NestedFactType)) { if (objectifiedFactType.UnaryRole != null) { // The uniqueness constraint on the objectified unary // role is the only possible candidate return(false); } else { int pidCandidateCount = 0; foreach (UniquenessConstraint uc in objectifiedFactType.GetInternalConstraints <UniquenessConstraint>()) { if (++pidCandidateCount > 1) { break; } } if (pidCandidateCount == 1) { return(false); } } } return(true); } UniquenessConstraint pid; return(null != (subtype = subtypeFact.Subtype) && null != (pid = subtype.PreferredIdentifier) && !pid.IsObjectifiedPreferredIdentifier); } return(base.IsPropertyDescriptorReadOnly(propertyDescriptor)); }
/// <summary> /// Add subtype links when possible /// </summary> /// <param name="element">An ModelHasFactType instance</param> /// <param name="store">The context store</param> /// <param name="notifyAdded">The listener to notify if elements are added during fixup</param> protected sealed override void ProcessElement(ModelHasFactType element, Store store, INotifyElementAdded notifyAdded) { SubtypeFact subTypeFact = element.FactType as SubtypeFact; ORMModel model; if (null != (subTypeFact = element.FactType as SubtypeFact) && !subTypeFact.IsDeleted && null != (model = subTypeFact.Model)) { ObjectType rolePlayer = subTypeFact.Subtype; FactType nestedFact = rolePlayer.NestedFactType; if (FactTypeShape.ShouldDrawObjectification(nestedFact)) { Diagram.FixUpDiagram(model, nestedFact); Diagram.FixUpDiagram(nestedFact, rolePlayer); } else { Diagram.FixUpDiagram(model, rolePlayer); } rolePlayer = subTypeFact.Supertype; nestedFact = rolePlayer.NestedFactType; if (FactTypeShape.ShouldDrawObjectification(nestedFact)) { Diagram.FixUpDiagram(model, nestedFact); Diagram.FixUpDiagram(nestedFact, rolePlayer); } else { Diagram.FixUpDiagram(model, rolePlayer); } object AllowMultipleShapes; Dictionary <object, object> topLevelContextInfo; bool containedAllowMultipleShapes; if (!(containedAllowMultipleShapes = (topLevelContextInfo = store.TransactionManager.CurrentTransaction.TopLevelTransaction.Context.ContextInfo).ContainsKey(AllowMultipleShapes = MultiShapeUtility.AllowMultipleShapes))) { topLevelContextInfo.Add(AllowMultipleShapes, null); } foreach (PresentationViewsSubject presentationViewsSubject in DomainRoleInfo.GetElementLinks <PresentationViewsSubject>(model, PresentationViewsSubject.SubjectDomainRoleId)) { ORMDiagram diagram; if ((diagram = presentationViewsSubject.Presentation as ORMDiagram) != null) { ObjectType subtype = subTypeFact.Subtype; // add a link shape for each object type shape on the diagram for the played role foreach (ObjectTypeShape shapeElement in MultiShapeUtility.FindAllShapesForElement <ObjectTypeShape>(diagram, subtype)) { diagram.FixUpLocalDiagram(subTypeFact); } FactType objectifiedFactType; if (null != (objectifiedFactType = subtype.NestedFactType)) { foreach (FactTypeShape shapeElement in MultiShapeUtility.FindAllShapesForElement <FactTypeShape>(diagram, objectifiedFactType)) { diagram.FixUpLocalDiagram(subTypeFact); } } } } if (!containedAllowMultipleShapes) { topLevelContextInfo.Remove(AllowMultipleShapes); } } }
public void ResolvePreferredTest1(Store store) { IElementDirectory directory = store.ElementDirectory; SubtypeFact FiveToTwo = (SubtypeFact)directory.GetElement(new Guid("9B85CC3F-FAA1-485B-A6CA-DE65165C6AE5")); SubtypeFact FiveToThree = (SubtypeFact)directory.GetElement(new Guid("C48F356A-DC20-4CD8-AD6A-EE4518622FFB")); SubtypeFact SixToFive = (SubtypeFact)directory.GetElement(new Guid("321CD412-8DAA-4D35-8D4E-D8D5915F07E0")); SubtypeFact SixToSeven = (SubtypeFact)directory.GetElement(new Guid("D6A4C2F2-3F99-4E2F-AB2F-407E03AB6F42")); SubtypeFact FiveToFour = (SubtypeFact)directory.GetElement(new Guid("DE1FC770-19A5-4CA9-AEF7-CE1204D80270")); SubtypeFact SevenToFour = (SubtypeFact)directory.GetElement(new Guid("71D29425-481E-445B-8F8A-63E9F29F761A")); ORMModel model = FiveToTwo.Model; RoleValueConstraint valueConstraint = (RoleValueConstraint)model.ConstraintsDictionary.GetElement("RoleValueConstraint1").SingleElement; myTestServices.LogValidationErrors("Expected three initial errors"); myTestServices.LogMessage("Scenario 1: Make 5->2 preferred path, sibling and downstream subtypes should all be preferred"); DomainTypeDescriptor.CreatePropertyDescriptor(FiveToTwo, SubtypeFact.ProvidesPreferredIdentifierDomainPropertyId).SetValue(FiveToTwo, true); myTestServices.LogValidationErrors("No errors expected"); myTestServices.LogMessage("5->4, 6->5, 6->7 are on the preferred path: " + (FiveToFour.ProvidesPreferredIdentifier && SixToFive.ProvidesPreferredIdentifier && SixToSeven.ProvidesPreferredIdentifier).ToString()); myTestServices.LogMessage("ValueConstraint should be a string type: " + valueConstraint.Text); myTestServices.LogMessage("Scenario 2: Make 5->3 preferred path, downstream subtypes are no ambiguous"); DomainTypeDescriptor.CreatePropertyDescriptor(FiveToThree, SubtypeFact.ProvidesPreferredIdentifierDomainPropertyId).SetValue(FiveToThree, true); myTestServices.LogValidationErrors("Two errors expected"); myTestServices.LogMessage("5->2, 5->4, 6->5, 6->7 are not preferred: " + (!(FiveToTwo.ProvidesPreferredIdentifier || FiveToFour.ProvidesPreferredIdentifier || SixToFive.ProvidesPreferredIdentifier || SixToSeven.ProvidesPreferredIdentifier)).ToString()); myTestServices.LogMessage("Scenario 3: Make 6->5 preferred path"); DomainTypeDescriptor.CreatePropertyDescriptor(SixToFive, SubtypeFact.ProvidesPreferredIdentifierDomainPropertyId).SetValue(SixToFive, true); myTestServices.LogValidationErrors("No errors expected"); myTestServices.LogMessage("6->7 is not on the preferred path: " + (!SixToSeven.ProvidesPreferredIdentifier).ToString()); myTestServices.LogMessage("ValueConstraint should be a number type: " + valueConstraint.Text); myTestServices.LogMessage("Scenario 4: Make 6->7 preferred path"); DomainTypeDescriptor.CreatePropertyDescriptor(SixToSeven, SubtypeFact.ProvidesPreferredIdentifierDomainPropertyId).SetValue(SixToSeven, true); myTestServices.LogValidationErrors("No errors expected"); myTestServices.LogMessage("6->5 is not on the preferred path: " + (!SixToFive.ProvidesPreferredIdentifier).ToString()); myTestServices.LogMessage("ValueConstraint should be a string type: " + valueConstraint.Text); myTestServices.LogMessage("Scenario 5: Delete 7->4 to break subtype structure"); using (Transaction t = store.TransactionManager.BeginTransaction("Break graph")) { SevenToFour.Delete(); t.Commit(); } myTestServices.LogValidationErrors("Expecting invalid graph, detached valuetype, and no reference scheme errors"); myTestServices.LogMessage("Scenario 6: Delete 6->5 to make graph valid"); using (Transaction t = store.TransactionManager.BeginTransaction("Graph OK")) { SixToFive.Delete(); t.Commit(); } myTestServices.LogValidationErrors("Expecting detached valuetype and no reference scheme errors"); myTestServices.LogMessage("Scenario 7: Set identifier on 7 to clear errors"); using (Transaction t = store.TransactionManager.BeginTransaction("Clear errors")) { SixToSeven.Supertype.ReferenceModeString = "id"; t.Commit(); } myTestServices.LogValidationErrors("No errors expected"); myTestServices.LogValidationErrors("Scenario 8: (Undo scenarios 5-7) Make 5->4 preferred path and give 4 an explicit id in one transaction"); store.UndoManager.Undo(); store.UndoManager.Undo(); store.UndoManager.Undo(); using (Transaction t = store.TransactionManager.BeginTransaction("Change id and make preferred in one transaction")) { // Note that doing this in the opposite order in two transactions has the same result FiveToFour.ProvidesPreferredIdentifier = true; FiveToFour.Supertype.ReferenceModeString = "id"; t.Commit(); } myTestServices.LogValidationErrors("No errors expected"); myTestServices.LogValidationErrors("Scenario 9: (Undo scenario 8) Make 5->4 preferred path then give 4 an explicit id to make 5 and 6 ambiguous"); store.UndoManager.Undo(); using (Transaction t = store.TransactionManager.BeginTransaction("Change preferred path")) { FiveToFour.ProvidesPreferredIdentifier = true; t.Commit(); } using (Transaction t = store.TransactionManager.BeginTransaction("Introduce id that interferes with split identifier path")) { FiveToFour.Supertype.ReferenceModeString = "id"; t.Commit(); } }