Пример #1
0
        private void SetInitialMultiplicity(BidirectionalAssociation element)
        {
            // valid bidirectional associations:
            // EF6 - entity to entity
            // EFCore - entity to entity, entity to dependent,  dependent to entity
            // EFCore5Plus - entity to entity, entity to dependent, dependent to entity

            ModelRoot modelRoot = element.Source.ModelRoot;
            EFVersion entityFrameworkVersion = modelRoot.EntityFrameworkVersion;

            if (entityFrameworkVersion == EFVersion.EF6)
            {
                if (element.Source.IsEntity() && element.Target.IsEntity())
                {
                    element.SourceMultiplicity = Multiplicity.One;
                    element.TargetMultiplicity = Multiplicity.ZeroMany;
                }
            }
            else if (entityFrameworkVersion == EFVersion.EFCore && !modelRoot.IsEFCore5Plus)
            {
                if (element.Source.IsEntity() && element.Target.IsEntity())
                {
                    element.SourceMultiplicity = Multiplicity.One;
                    element.TargetMultiplicity = Multiplicity.ZeroMany;
                }

                if (element.Source.IsEntity() && element.Target.IsDependent())
                {
                    element.SourceMultiplicity = Multiplicity.One;
                    element.TargetMultiplicity = Multiplicity.One;
                }

                if (element.Source.IsDependent() && element.Target.IsEntity())
                {
                    element.SourceMultiplicity = Multiplicity.One;
                    element.TargetMultiplicity = Multiplicity.One;
                }
            }
            else if (entityFrameworkVersion == EFVersion.EFCore && modelRoot.IsEFCore5Plus)
            {
                if (element.Source.IsEntity() && element.Target.IsEntity())
                {
                    element.SourceMultiplicity = Multiplicity.One;
                    element.TargetMultiplicity = Multiplicity.ZeroMany;
                }

                if (element.Source.IsEntity() && element.Target.IsDependent())
                {
                    element.SourceMultiplicity = Multiplicity.One;
                    element.TargetMultiplicity = Multiplicity.One;
                }

                if (element.Source.IsDependent() && element.Target.IsEntity())
                {
                    element.SourceMultiplicity = Multiplicity.One;
                    element.TargetMultiplicity = Multiplicity.One;
                }
            }
        }
        public override string GetToolTipText(DiagramItem item)
        {
            BidirectionalAssociation association = item.Shape.ModelElement as BidirectionalAssociation;

            return(association != null
                   ? $"{association.Source.Name}.{association.TargetPropertyName} <--> {association.Target.Name}.{association.SourcePropertyName}"
                   : string.Empty);
        }
Пример #3
0
        private void OnMenuSplitAssociation(object sender, EventArgs e)
        {
            BidirectionalAssociation selected = CurrentSelection.OfType <BidirectionalConnector>()
                                                .Select(connector => connector.ModelElement)
                                                .Cast <BidirectionalAssociation>()
                                                .Single();

            ((EFModelDocData)CurrentDocData).Split(selected);
        }
 /// <summary>
 ///    Called after the IsSourceImplementNotifyTracking property changes.
 /// </summary>
 /// <param name="element">The model element that has the property that changed. </param>
 /// <param name="oldValue">The previous value of the property. </param>
 /// <param name="newValue">The new value of the property. </param>
 protected override void OnValueChanged(BidirectionalAssociation element, bool oldValue, bool newValue)
 {
     base.OnValueChanged(element, oldValue, newValue);
     if (!element.Store.InUndoRedoOrRollback && newValue)
     {
         DomainPropertyInfo propInfo = element.Store.DomainDataDirectory.GetDomainProperty(SourceImplementNotifyDomainPropertyId);
         propInfo.NotifyValueChange(element);
     }
 }
Пример #5
0
        private static ElementLink ConnectModelClassToModelClass(ModelClass sourceAccepted, ModelClass targetAccepted)
        {
            ElementLink result = new BidirectionalAssociation(sourceAccepted, targetAccepted);

            if (DomainClassInfo.HasNameProperty(result))
            {
                DomainClassInfo.SetUniqueName(result);
            }

            return(result);
        }
Пример #6
0
        private static string GetDisplayPropertyFromModelClassForSourcesCompartment(ModelElement element)
        {
            BidirectionalAssociation association = (BidirectionalAssociation)element;
            ModelClass source = association.Source;

            if (!string.IsNullOrEmpty(association.SourcePropertyName))
            {
                return($"{association.SourcePropertyName} : {source.Name}");
            }

            return(source.Name);
        }
Пример #7
0
      private void ProcessBidirectionalAssociations(List<ModelBidirectionalAssociation> bidirectionalAssociations)
      {
         foreach (ModelBidirectionalAssociation data in bidirectionalAssociations)
         {
            if (Store.Get<BidirectionalAssociation>()
                     .Any(x => x.Target.FullName == data.TargetClassFullName &&
                               x.Source.FullName == data.SourceClassFullName &&
                               x.TargetPropertyName == data.TargetPropertyName &&
                               x.SourcePropertyName == data.SourcePropertyName))
               continue;

            if (Store.Get<BidirectionalAssociation>()
                     .Any(x => x.Source.FullName == data.TargetClassFullName &&
                               x.Target.FullName == data.SourceClassFullName &&
                               x.SourcePropertyName == data.TargetPropertyName &&
                               x.TargetPropertyName == data.SourcePropertyName))
               continue;


            ModelClass source = Store.Get<ModelClass>().FirstOrDefault(c => c.FullName == data.SourceClassFullName);

            if (source == null)
               continue;

            ModelClass target = Store.Get<ModelClass>().FirstOrDefault(c => c.Name == data.TargetClassName && c.Namespace == data.TargetClassNamespace);

            if (target == null)
               continue;

            // ReSharper disable once UnusedVariable
            BidirectionalAssociation element = new BidirectionalAssociation(Store,
                                                   new[]
                                                   {
                                                      new RoleAssignment(BidirectionalAssociation.BidirectionalSourceDomainRoleId, source),
                                                      new RoleAssignment(BidirectionalAssociation.BidirectionalTargetDomainRoleId, target)
                                                   },
                                                   new[]
                                                   {
                                                      new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, ConvertMultiplicity(data.SourceMultiplicity)), 
                                                      new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, ConvertMultiplicity(data.TargetMultiplicity)), 
                                                      new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, data.TargetPropertyName), 
                                                      new PropertyAssignment(Association.TargetSummaryDomainPropertyId, data.TargetSummary), 
                                                      new PropertyAssignment(Association.TargetDescriptionDomainPropertyId, data.TargetDescription), 
                                                      new PropertyAssignment(BidirectionalAssociation.SourcePropertyNameDomainPropertyId, data.SourcePropertyName), 
                                                      new PropertyAssignment(BidirectionalAssociation.SourceSummaryDomainPropertyId, data.SourceSummary), 
                                                      new PropertyAssignment(BidirectionalAssociation.SourceDescriptionDomainPropertyId, data.SourceDescription),
                                                   });
         }
      }
        public override void ElementAdded(ElementAddedEventArgs e)
        {
            base.ElementAdded(e);

            BidirectionalAssociation element = (BidirectionalAssociation)e.ModelElement;
            Store       store   = element.Store;
            Transaction current = store.TransactionManager.CurrentTransaction;

            if (current.IsSerializing)
            {
                return;
            }

            PresentationHelper.UpdateAssociationDisplay(element);
        }
      private static void CheckSourceForDisplayText(BidirectionalAssociation bidirectionalAssociation)
      {
         Match match = DisplayAttributeRegex.Match(bidirectionalAssociation.SourceCustomAttributes);

         // is there a custom attribute for [Display]?
         if (match != Match.Empty)
         {
            // if SourceDisplayText is empty, move the Name down to SourceDisplayText
            if (string.IsNullOrWhiteSpace(bidirectionalAssociation.SourceDisplayText))
               bidirectionalAssociation.SourceDisplayText = match.Groups[3].Value;

            // if custom attribute's Name matches SourceDisplayText, remove that attribute, leaving other custom attributes if present
            if (match.Groups[3].Value == bidirectionalAssociation.SourceDisplayText)
               bidirectionalAssociation.SourceCustomAttributes = match.Groups[1].Value + match.Groups[4].Value;
         }
      }
            /// <summary>Performs the reset operation for the IsSourceImplementNotifyTracking property for a model element.</summary>
            /// <param name="element">The model element that has the property to reset.</param>
            internal void ResetValue(BidirectionalAssociation element)
            {
                object calculatedValue = null;

                try
                {
                    calculatedValue = element.Source?.ImplementNotify;
                }
                catch (NullReferenceException) { }
                catch (Exception e)
                {
                    if (CriticalException.IsCriticalException(e))
                    {
                        throw;
                    }
                }

                if (calculatedValue != null && element.SourceImplementNotify == (bool)calculatedValue)
                {
                    element.isSourceImplementNotifyTrackingPropertyStorage = true;
                }
            }
Пример #11
0
        /// <summary>
        /// OnBeforePaint is called at the start of the ShapeElement's painting.
        /// It provides an opportunity for developers to update and override resources
        /// before they're used in painting.
        /// </summary>
        /// <remarks>
        /// You can override existing resources by calling StyleSet.OverrideXXX and
        /// changing the specific setting that you would like.
        /// </remarks>
        protected override void OnBeforePaint()
        {
            if (ModelElement is Association element)
            {
                BidirectionalAssociation bidirectionalElement = ModelElement as BidirectionalAssociation;
                bool hasAutoInclude = element.Source.ModelRoot.IsEFCore5Plus && (element.TargetAutoInclude || bidirectionalElement?.SourceAutoInclude == true);

                if (hasAutoInclude)
                {
                    PenSettings settings = StyleSet.GetOverriddenPenSettings(DiagramPens.ConnectionLine) ?? new PenSettings();
                    settings.Width = 0.05f;
                    StyleSet.OverridePen(DiagramPens.ConnectionLine, settings);
                }
                else
                {
                    StyleSet.ClearPenOverride(DiagramPens.ConnectionLine);
                }
            }
            else
            {
                StyleSet.ClearPenOverride(DiagramPens.ConnectionLine);
            }
        }
Пример #12
0
        private void SetSourcePropertyName(BidirectionalAssociation element)
        {
            if (string.IsNullOrEmpty(element.SourcePropertyName))
            {
                string rootName = element.SourceMultiplicity == Multiplicity.ZeroMany && ModelRoot.PluralizationService?.IsSingular(element.Source.Name) == true
                                 ? ModelRoot.PluralizationService.Pluralize(element.Source.Name)
                                 : element.Source.Name;

                string identifierName = rootName;
                int    index          = 0;

                ModelClass modelClass = element.Target;

                while (modelClass.HasPropertyNamed(identifierName) ||
                       modelClass.AllSubclasses.Any(c => c.HasPropertyNamed(identifierName)) ||
                       modelClass.AllSuperclasses.Any(c => c.HasPropertyNamed(identifierName)))
                {
                    identifierName = $"{rootName}_{++index}";
                }

                element.SourcePropertyName = identifierName;
            }
        }
        /// <summary>
        ///    Returns the property descriptors for the described Association domain class, adding tracking property
        ///    descriptor(s).
        /// </summary>
        private PropertyDescriptorCollection GetCustomProperties(Attribute[] attributes)
        {
            // Get the default property descriptors from the base class
            PropertyDescriptorCollection propertyDescriptors = base.GetProperties(attributes);

            //Add the descriptor for the tracking property.
            if (ModelElement is Association association)
            {
                ModelRoot modelRoot = association.Source.ModelRoot;
                storeDomainDataDirectory = association.Store.DomainDataDirectory;
                BidirectionalAssociation bidirectionalAssociation = association as BidirectionalAssociation;

                // show FKPropertyName only when possible and required
                if (!modelRoot.ExposeForeignKeys ||
                    (association.SourceRole != EndpointRole.Dependent && association.TargetRole != EndpointRole.Dependent))
                {
                    propertyDescriptors.Remove("FKPropertyName");
                }

                // EF6 can't have declared foreign keys for 1..1 / 0-1..1 / 1..0-1 / 0-1..0-1 relationships
                if (modelRoot.EntityFrameworkVersion == EFVersion.EF6 &&
                    association.SourceMultiplicity != Multiplicity.ZeroMany &&
                    association.TargetMultiplicity != Multiplicity.ZeroMany)
                {
                    propertyDescriptors.Remove("FKPropertyName");
                }

                // no FKs for aggregates
                if (association.Source.IsDependentType || association.Target.IsDependentType)
                {
                    propertyDescriptors.Remove("FKPropertyName");
                }

                // only display roles for 1..1 and 0-1..0-1 associations
                if ((association.SourceMultiplicity != Multiplicity.One || association.TargetMultiplicity != Multiplicity.One) &&
                    (association.SourceMultiplicity != Multiplicity.ZeroOne || association.TargetMultiplicity != Multiplicity.ZeroOne))
                {
                    propertyDescriptors.Remove("SourceRole");
                    propertyDescriptors.Remove("TargetRole");
                }

                // only display delete behavior on the principal end
                // except that owned types don't have deletiion behavior choices
                if (association.SourceRole != EndpointRole.Principal || association.Source.IsDependentType || association.Target.IsDependentType)
                {
                    propertyDescriptors.Remove("SourceDeleteAction");
                }

                if (association.TargetRole != EndpointRole.Principal || association.Source.IsDependentType || association.Target.IsDependentType)
                {
                    propertyDescriptors.Remove("TargetDeleteAction");
                }

                // only show JoinTableName if is *..* association
                if (association.SourceMultiplicity != Multiplicity.ZeroMany || association.TargetMultiplicity != Multiplicity.ZeroMany)
                {
                    propertyDescriptors.Remove("JoinTableName");
                }

                // implementNotify implicitly defines autoproperty as false, so we don't display it
                if (association.TargetImplementNotify)
                {
                    propertyDescriptors.Remove("TargetAutoProperty");
                }
                if (bidirectionalAssociation != null && bidirectionalAssociation.SourceImplementNotify)
                {
                    propertyDescriptors.Remove("SourceAutoProperty");
                }

                // we're only allowing ..1 and ..0-1 associations to have backing fields
                if (association.TargetMultiplicity == Multiplicity.ZeroMany)
                {
                    propertyDescriptors.Remove("TargetAutoProperty");
                }
                if (bidirectionalAssociation != null && bidirectionalAssociation.SourceMultiplicity == Multiplicity.ZeroMany)
                {
                    propertyDescriptors.Remove("SourceAutoProperty");
                }

                // EF6 doesn't support property access modes
                if (modelRoot.EntityFrameworkVersion == EFVersion.EF6)
                {
                    propertyDescriptors.Remove("TargetPropertyAccessMode");
                    propertyDescriptors.Remove("SourcePropertyAccessMode");
                }

                // only show backing field name and property access mode if not an autoproperty
                if (association.TargetAutoProperty)
                {
                    propertyDescriptors.Remove("TargetBackingFieldName");
                    propertyDescriptors.Remove("TargetPropertyAccessMode");
                }

                if (bidirectionalAssociation == null || bidirectionalAssociation.SourceAutoProperty)
                {
                    propertyDescriptors.Remove("SourceBackingFieldName");
                    propertyDescriptors.Remove("SourcePropertyAccessMode");
                }

                /********************************************************************************/

                //Add the descriptors for the tracking properties

                propertyDescriptors.Add(new TrackingPropertyDescriptor(association
                                                                       , storeDomainDataDirectory.GetDomainProperty(Association.CollectionClassDomainPropertyId)
                                                                       , storeDomainDataDirectory.GetDomainProperty(Association.IsCollectionClassTrackingDomainPropertyId)
                                                                       , new Attribute[]
                {
                    new DisplayNameAttribute("Collection Class")
                    , new DescriptionAttribute("Type of collections generated. Overrides the default collection class for the model")
                    , new CategoryAttribute("Code Generation")
                }));

                if (association.TargetMultiplicity == Multiplicity.One || association.TargetMultiplicity == Multiplicity.ZeroOne)
                {
                    propertyDescriptors.Add(new TrackingPropertyDescriptor(association
                                                                           , storeDomainDataDirectory.GetDomainProperty(Association.TargetImplementNotifyDomainPropertyId)
                                                                           , storeDomainDataDirectory.GetDomainProperty(Association.IsTargetImplementNotifyTrackingDomainPropertyId)
                                                                           , new Attribute[]
                    {
                        new DisplayNameAttribute("Implement INotifyPropertyChanged")
                        , new DescriptionAttribute("Should this end participate in INotifyPropertyChanged activities? "
                                                   + "Only valid for non-collection targets.")
                        , new CategoryAttribute("End 2")
                    }));

                    propertyDescriptors.Add(new TrackingPropertyDescriptor(association
                                                                           , storeDomainDataDirectory.GetDomainProperty(Association.TargetAutoPropertyDomainPropertyId)
                                                                           , storeDomainDataDirectory.GetDomainProperty(Association.IsTargetAutoPropertyTrackingDomainPropertyId)
                                                                           , new Attribute[]
                    {
                        new DisplayNameAttribute("End1 Is Auto Property")
                        , new DescriptionAttribute("If false, generates a backing field and a partial method to hook getting and setting the property. "
                                                   + "If true, generates a simple auto property. Only valid for non-collection properties.")
                        , new CategoryAttribute("End 2")
                    }));
                }

                if (bidirectionalAssociation?.SourceMultiplicity == Multiplicity.One || bidirectionalAssociation?.SourceMultiplicity == Multiplicity.ZeroOne)
                {
                    propertyDescriptors.Add(new TrackingPropertyDescriptor(bidirectionalAssociation
                                                                           , storeDomainDataDirectory.GetDomainProperty(BidirectionalAssociation.SourceImplementNotifyDomainPropertyId)
                                                                           , storeDomainDataDirectory.GetDomainProperty(BidirectionalAssociation.IsSourceImplementNotifyTrackingDomainPropertyId)
                                                                           , new Attribute[]
                    {
                        new DisplayNameAttribute("Implement INotifyPropertyChanged")
                        , new DescriptionAttribute("Should this end participate in INotifyPropertyChanged activities? "
                                                   + "Only valid for non-collection targets.")
                        , new CategoryAttribute("End 1")
                    }));

                    propertyDescriptors.Add(new TrackingPropertyDescriptor(association
                                                                           , storeDomainDataDirectory.GetDomainProperty(BidirectionalAssociation.SourceAutoPropertyDomainPropertyId)
                                                                           , storeDomainDataDirectory.GetDomainProperty(BidirectionalAssociation.IsSourceAutoPropertyTrackingDomainPropertyId)
                                                                           , new Attribute[]
                    {
                        new DisplayNameAttribute("End2 Is Auto Property")
                        , new DescriptionAttribute("If false, generates a backing field and a partial method to hook getting and setting the property. "
                                                   + "If true, generates a simple auto property. Only valid for non-collection properties.")
                        , new CategoryAttribute("End 1")
                    }));
                }
            }

            // Return the property descriptors for this element
            return(propertyDescriptors);
        }
Пример #14
0
        public override void ElementPropertyChanged(ElementPropertyChangedEventArgs e)
        {
            base.ElementPropertyChanged(e);

            Association element = (Association)e.ModelElement;

            if (element.IsDeleted)
            {
                return;
            }

            Store       store   = element.Store;
            Transaction current = store.TransactionManager.CurrentTransaction;

            if (current.IsSerializing)
            {
                return;
            }

            if (Equals(e.NewValue, e.OldValue))
            {
                return;
            }

            List <string>            errorMessages            = EFCoreValidator.GetErrors(element).ToList();
            BidirectionalAssociation bidirectionalAssociation = element as BidirectionalAssociation;

            switch (e.DomainProperty.Name)
            {
            case "SourceCustomAttributes":

                if (bidirectionalAssociation != null && !string.IsNullOrWhiteSpace(bidirectionalAssociation.SourceCustomAttributes))
                {
                    bidirectionalAssociation.SourceCustomAttributes = $"[{bidirectionalAssociation.SourceCustomAttributes.Trim('[', ']')}]";
                    CheckSourceForDisplayText(bidirectionalAssociation);
                }

                break;

            case "SourceDisplayText":

                if (bidirectionalAssociation != null)
                {
                    CheckSourceForDisplayText(bidirectionalAssociation);
                }

                break;

            case "SourceMultiplicity":
                Multiplicity sourceMultiplicity = (Multiplicity)e.NewValue;

                // change unidirectional source cardinality
                // if target is dependent
                //    source cardinality is 0..1 or 1
                if (element.Target.IsDependentType && sourceMultiplicity == Multiplicity.ZeroMany)
                {
                    errorMessages.Add($"Can't have a 0..* association from {element.Target.Name} to dependent type {element.Source.Name}");

                    break;
                }

                if ((sourceMultiplicity == Multiplicity.One && element.TargetMultiplicity == Multiplicity.One) ||
                    (sourceMultiplicity == Multiplicity.ZeroOne && element.TargetMultiplicity == Multiplicity.ZeroOne))
                {
                    if (element.SourceRole != EndpointRole.NotSet)
                    {
                        element.SourceRole = EndpointRole.NotSet;
                    }

                    if (element.TargetRole != EndpointRole.NotSet)
                    {
                        element.TargetRole = EndpointRole.NotSet;
                    }
                }
                else
                {
                    SetEndpointRoles(element);
                }

                // cascade delete behavior could now be illegal. Reset to default
                element.SourceDeleteAction = DeleteAction.Default;
                element.TargetDeleteAction = DeleteAction.Default;

                break;

            case "SourcePropertyName":
                string sourcePropertyNameErrorMessage = ValidateAssociationIdentifier(element, element.Target, (string)e.NewValue);

                if (EFModelDiagram.IsDropping && sourcePropertyNameErrorMessage != null)
                {
                    element.Delete();
                }
                else
                {
                    errorMessages.Add(sourcePropertyNameErrorMessage);
                }

                break;

            case "SourceRole":

                if (element.Source.IsDependentType)
                {
                    element.SourceRole = EndpointRole.Dependent;
                    element.TargetRole = EndpointRole.Principal;
                }
                else if (!SetEndpointRoles(element))
                {
                    if (element.SourceRole == EndpointRole.Dependent && element.TargetRole != EndpointRole.Principal)
                    {
                        element.TargetRole = EndpointRole.Principal;
                    }
                    else if (element.SourceRole == EndpointRole.Principal && element.TargetRole != EndpointRole.Dependent)
                    {
                        element.TargetRole = EndpointRole.Dependent;
                    }
                }

                break;

            case "TargetCustomAttributes":

                if (!string.IsNullOrWhiteSpace(element.TargetCustomAttributes))
                {
                    element.TargetCustomAttributes = $"[{element.TargetCustomAttributes.Trim('[', ']')}]";
                    CheckTargetForDisplayText(element);
                }

                break;

            case "TargetDisplayText":

                CheckTargetForDisplayText(element);

                break;

            case "TargetMultiplicity":
                Multiplicity newTargetMultiplicity = (Multiplicity)e.NewValue;

                // change unidirectional target cardinality
                // if target is dependent
                //    target cardinality must be 0..1 or 1
                if (element.Target.IsDependentType && newTargetMultiplicity == Multiplicity.ZeroMany)
                {
                    errorMessages.Add($"Can't have a 0..* association from {element.Source.Name} to dependent type {element.Target.Name}");

                    break;
                }

                if ((element.SourceMultiplicity == Multiplicity.One && newTargetMultiplicity == Multiplicity.One) ||
                    (element.SourceMultiplicity == Multiplicity.ZeroOne && newTargetMultiplicity == Multiplicity.ZeroOne))
                {
                    if (element.SourceRole != EndpointRole.NotSet)
                    {
                        element.SourceRole = EndpointRole.NotSet;
                    }

                    if (element.TargetRole != EndpointRole.NotSet)
                    {
                        element.TargetRole = EndpointRole.NotSet;
                    }
                }
                else
                {
                    SetEndpointRoles(element);
                }

                // cascade delete behavior could now be illegal. Reset to default
                element.SourceDeleteAction = DeleteAction.Default;
                element.TargetDeleteAction = DeleteAction.Default;

                break;

            case "TargetPropertyName":

                // if we're creating an association via drag/drop, it's possible the existing property name
                // is the same as the default property name. The default doesn't get created until the transaction is
                // committed, so the drop's action will cause a name clash. Remove the clashing property, but
                // only if drag/drop.

                string targetPropertyNameErrorMessage = ValidateAssociationIdentifier(element, element.Source, (string)e.NewValue);

                if (EFModelDiagram.IsDropping && targetPropertyNameErrorMessage != null)
                {
                    element.Delete();
                }
                else
                {
                    errorMessages.Add(targetPropertyNameErrorMessage);
                }

                break;

            case "TargetRole":

                if (element.Target.IsDependentType)
                {
                    element.SourceRole = EndpointRole.Principal;
                    element.TargetRole = EndpointRole.Dependent;
                }
                else if (!SetEndpointRoles(element))
                {
                    if (element.TargetRole == EndpointRole.Dependent && element.SourceRole != EndpointRole.Principal)
                    {
                        element.SourceRole = EndpointRole.Principal;
                    }
                    else if (element.TargetRole == EndpointRole.Principal && element.SourceRole != EndpointRole.Dependent)
                    {
                        element.SourceRole = EndpointRole.Dependent;
                    }
                }

                break;
            }

            errorMessages = errorMessages.Where(m => m != null).ToList();

            if (errorMessages.Any())
            {
                current.Rollback();
                ErrorDisplay.Show(string.Join("\n", errorMessages));
            }
        }
 /// <summary>
 ///    Method to set IsSourceImplementNotifyTracking to false so that this instance of this tracking property is not
 ///    storage-based.
 /// </summary>
 /// <param name="element">
 ///    The element on which to reset the property value.
 /// </param>
 internal void PreResetValue(BidirectionalAssociation element)
 {
     // Force the IsSourceImplementNotifyTracking property to false so that the value
     // of the SourceImplementNotify property is retrieved from storage.
     element.isSourceImplementNotifyTrackingPropertyStorage = false;
 }
Пример #16
0
      private void ProcessBidirectionalAssociations(ParsingModels.ModelClass modelClass)
      {
         List<ModelBidirectionalAssociation> bidirectionalAssociations = modelClass.BidirectionalAssociations;

         foreach (ModelBidirectionalAssociation data in bidirectionalAssociations)
         {
            if (Store.ModelRoot().EntityFrameworkVersion == EFVersion.EF6
             && data.SourceMultiplicity != ParsingModels.Multiplicity.ZeroMany
             && data.TargetMultiplicity != ParsingModels.Multiplicity.ZeroMany)
               data.ForeignKey = null;

            BidirectionalAssociation existing = Store.GetAll<BidirectionalAssociation>()
                                                     .FirstOrDefault(x => x.Target.Name == data.TargetClassName
                                                                       && x.Source.Name == data.SourceClassName
                                                                       && x.Source.Name == modelClass.Name // just to be sure
                                                                       && x.TargetPropertyName == data.TargetPropertyName
                                                                       && x.SourcePropertyName == data.SourcePropertyName)
                                             ?? Store.GetAll<BidirectionalAssociation>()
                                                     .FirstOrDefault(x => x.Source.Name == data.TargetClassName
                                                                       && x.Target.Name == data.SourceClassName
                                                                       && x.Target.Name == modelClass.Name // just to be sure
                                                                       && x.SourcePropertyName == data.TargetPropertyName
                                                                       && x.TargetPropertyName == data.SourcePropertyName);

            if (existing != null)
            {
               if (string.IsNullOrWhiteSpace(existing.FKPropertyName) && !string.IsNullOrWhiteSpace(data.ForeignKey))
               {
                  existing.FKPropertyName = string.Join(",", data.ForeignKey.Split(',').ToList().Select(p => p.Split('/').Last().Split(' ').Last()));
                  existing.Source.ModelRoot.ExposeForeignKeys = true;
               }

               continue;
            }

            ModelClass source = Store.GetAll<ModelClass>().FirstOrDefault(c => c.Name == data.SourceClassName);
            ModelClass target = Store.GetAll<ModelClass>().FirstOrDefault(c => c.Name == data.TargetClassName);

            if (source == null || target == null || source.FullName != modelClass.FullName)
               continue;

            BidirectionalAssociation elementLink = (BidirectionalAssociation)BidirectionalAssociationBuilder.Connect(source, target);
            elementLink.SourceMultiplicity = ConvertMultiplicity(data.SourceMultiplicity);
            elementLink.TargetMultiplicity = ConvertMultiplicity(data.TargetMultiplicity);
            elementLink.TargetPropertyName = data.TargetPropertyName;
            elementLink.TargetSummary = data.TargetSummary;
            elementLink.TargetDescription = data.TargetDescription;
            elementLink.FKPropertyName = data.ForeignKey;
            elementLink.SourceRole = ConvertRole(data.SourceRole);
            elementLink.TargetRole = ConvertRole(data.TargetRole);
            elementLink.SourcePropertyName = data.SourcePropertyName;
            elementLink.SourceSummary = data.SourceSummary;
            elementLink.SourceDescription = data.SourceDescription;

            // ReSharper disable once UnusedVariable
            //BidirectionalAssociation element = new BidirectionalAssociation(Store,
            //                                       new[]
            //                                       {
            //                                          new RoleAssignment(BidirectionalAssociation.BidirectionalSourceDomainRoleId, source),
            //                                          new RoleAssignment(BidirectionalAssociation.BidirectionalTargetDomainRoleId, target)
            //                                       },
            //                                       new[]
            //                                       {
            //                                          new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, ConvertMultiplicity(data.SourceMultiplicity)),
            //                                          new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, ConvertMultiplicity(data.TargetMultiplicity)),
            //                                          new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, data.TargetPropertyName),
            //                                          new PropertyAssignment(Association.TargetSummaryDomainPropertyId, data.TargetSummary),
            //                                          new PropertyAssignment(Association.TargetDescriptionDomainPropertyId, data.TargetDescription),
            //                                          new PropertyAssignment(Association.FKPropertyNameDomainPropertyId, data.ForeignKey),
            //                                          new PropertyAssignment(Association.SourceRoleDomainPropertyId, ConvertRole(data.SourceRole)),
            //                                          new PropertyAssignment(Association.TargetRoleDomainPropertyId, ConvertRole(data.TargetRole)),
            //                                          new PropertyAssignment(BidirectionalAssociation.SourcePropertyNameDomainPropertyId, data.SourcePropertyName),
            //                                          new PropertyAssignment(BidirectionalAssociation.SourceSummaryDomainPropertyId, data.SourceSummary),
            //                                          new PropertyAssignment(BidirectionalAssociation.SourceDescriptionDomainPropertyId, data.SourceDescription),
            //                                       });
            AssociationChangedRules.SetEndpointRoles(elementLink);
            AssociationChangedRules.FixupForeignKeys(elementLink);

            // we could have a situation where there are no roles assigned (if 0/1-0/1 or 1-1). If we have exposed foreign keys, though, we can figure those out.
            if ((elementLink.SourceMultiplicity != Multiplicity.ZeroMany || elementLink.TargetMultiplicity != Multiplicity.ZeroMany)
             && (elementLink.SourceRole == EndpointRole.NotSet || elementLink.TargetRole == EndpointRole.NotSet)
             && !string.IsNullOrEmpty(elementLink.FKPropertyName))
            {
               // which, if any, end has the foreign key properties in it?
               string firstFKPropertyName = elementLink.FKPropertyName.Split(',').First();

               if (elementLink.Source.AllPropertyNames.Contains(firstFKPropertyName))
               {
                  elementLink.SourceRole = EndpointRole.Dependent;
                  elementLink.TargetRole = EndpointRole.Principal;
               }
               else if (elementLink.Target.AllPropertyNames.Contains(firstFKPropertyName))
               {
                  elementLink.TargetRole = EndpointRole.Dependent;
                  elementLink.SourceRole = EndpointRole.Principal;
               }
            }
         }
      }
Пример #17
0
        private void ProcessAssociation([NotNull] ModelClass source, [NotNull] ModelClass target, [NotNull] PropertyDeclarationSyntax propertyDecl, bool toMany = false)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            if (propertyDecl == null)
            {
                throw new ArgumentNullException(nameof(propertyDecl));
            }

            Transaction tx = Store.TransactionManager.CurrentTransaction == null
                             ? Store.TransactionManager.BeginTransaction()
                             : null;

            try
            {
                string propertyName = propertyDecl.Identifier.ToString();

                // since we don't have enough information from the code, we'll create unidirectional associations
                // cardinality 1 on the source end, 0..1 or 0..* on the target, depending on the parameter

                XMLDocumentation xmlDocumentation = new XMLDocumentation(propertyDecl);

                // if the association doesn't yet exist, create it
                if (!Store.ElementDirectory
                    .AllElements
                    .OfType <UnidirectionalAssociation>()
                    .Any(a => a.Source == source &&
                         a.Target == target &&
                         a.TargetPropertyName == propertyName))
                {
                    // if there's a unidirectional going the other direction, we'll whack that one and make a bidirectional
                    // otherwise, proceed as planned
                    UnidirectionalAssociation compliment = Store.ElementDirectory
                                                           .AllElements
                                                           .OfType <UnidirectionalAssociation>()
                                                           .FirstOrDefault(a => a.Source == target &&
                                                                           a.Target == source);

                    if (compliment == null)
                    {
                        UnidirectionalAssociation _ =
                            new UnidirectionalAssociation(Store,
                                                          new[]
                        {
                            new RoleAssignment(UnidirectionalAssociation.UnidirectionalSourceDomainRoleId, source),
                            new RoleAssignment(UnidirectionalAssociation.UnidirectionalTargetDomainRoleId, target)
                        },
                                                          new[]
                        {
                            new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, Multiplicity.One),

                            new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, toMany ? Multiplicity.ZeroMany : Multiplicity.ZeroOne),
                            new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, propertyName),
                            new PropertyAssignment(Association.TargetSummaryDomainPropertyId, xmlDocumentation.Summary),
                            new PropertyAssignment(Association.TargetDescriptionDomainPropertyId, xmlDocumentation.Description)
                        });
                    }
                    else
                    {
                        compliment.Delete();

                        BidirectionalAssociation _ =
                            new BidirectionalAssociation(Store,
                                                         new[]
                        {
                            new RoleAssignment(BidirectionalAssociation.BidirectionalSourceDomainRoleId, source),
                            new RoleAssignment(BidirectionalAssociation.BidirectionalTargetDomainRoleId, target)
                        },
                                                         new[]
                        {
                            new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, compliment.TargetMultiplicity),
                            new PropertyAssignment(BidirectionalAssociation.SourcePropertyNameDomainPropertyId, compliment.TargetPropertyName),
                            new PropertyAssignment(BidirectionalAssociation.SourceSummaryDomainPropertyId, compliment.TargetSummary),
                            new PropertyAssignment(BidirectionalAssociation.SourceDescriptionDomainPropertyId, compliment.TargetDescription),

                            new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, toMany ? Multiplicity.ZeroMany : Multiplicity.ZeroOne),
                            new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, propertyName),
                            new PropertyAssignment(Association.TargetSummaryDomainPropertyId, xmlDocumentation.Summary),
                            new PropertyAssignment(Association.TargetDescriptionDomainPropertyId, xmlDocumentation.Description)
                        });
                    }
                }
            }
            catch
            {
                tx.Rollback();
                tx = null;

                throw;
            }
            finally
            {
                tx?.Commit();
            }
        }
Пример #18
0
      private void ProcessBidirectionalAssociations(ParsingModels.ModelClass modelClass)
      {
         List<ModelBidirectionalAssociation> bidirectionalAssociations = modelClass.BidirectionalAssociations;

         foreach (ModelBidirectionalAssociation data in bidirectionalAssociations)
         {
            if (Store.ModelRoot().EntityFrameworkVersion == EFVersion.EF6 && data.SourceMultiplicity != ParsingModels.Multiplicity.ZeroMany && data.TargetMultiplicity != ParsingModels.Multiplicity.ZeroMany)
               data.ForeignKey = null;

            BidirectionalAssociation existing = Store.GetAll<BidirectionalAssociation>()
                                                     .FirstOrDefault(x => x.Target.Name == data.TargetClassName
                                                                       && x.Source.Name == data.SourceClassName
                                                                       && x.Source.Name == modelClass.Name // just to be sure
                                                                       && x.TargetPropertyName == data.TargetPropertyName
                                                                       && x.SourcePropertyName == data.SourcePropertyName)
                                             ?? Store.GetAll<BidirectionalAssociation>()
                                                     .FirstOrDefault(x => x.Source.Name == data.TargetClassName
                                                                       && x.Target.Name == data.SourceClassName
                                                                       && x.Target.Name == modelClass.Name // just to be sure
                                                                       && x.SourcePropertyName == data.TargetPropertyName
                                                                       && x.TargetPropertyName == data.SourcePropertyName);

            if (existing != null)
            {
               if (string.IsNullOrWhiteSpace(existing.FKPropertyName) && !string.IsNullOrWhiteSpace(data.ForeignKey))
               {
                  existing.FKPropertyName = data.ForeignKey;
                  existing.Source.ModelRoot.ExposeForeignKeys = true;
               }

               continue;
            }

            ModelClass source = Store.GetAll<ModelClass>().FirstOrDefault(c => c.Name == data.SourceClassName);
            ModelClass target = Store.GetAll<ModelClass>().FirstOrDefault(c => c.Name == data.TargetClassName);

            if (source == null || target == null || source.FullName != modelClass.FullName)
               continue;

            // ReSharper disable once UnusedVariable
            BidirectionalAssociation element = new BidirectionalAssociation(Store,
                                                   new[]
                                                   {
                                                      new RoleAssignment(BidirectionalAssociation.BidirectionalSourceDomainRoleId, source),
                                                      new RoleAssignment(BidirectionalAssociation.BidirectionalTargetDomainRoleId, target)
                                                   },
                                                   new[]
                                                   {
                                                      new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, ConvertMultiplicity(data.SourceMultiplicity)),
                                                      new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, ConvertMultiplicity(data.TargetMultiplicity)),
                                                      new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, data.TargetPropertyName),
                                                      new PropertyAssignment(Association.TargetSummaryDomainPropertyId, data.TargetSummary),
                                                      new PropertyAssignment(Association.TargetDescriptionDomainPropertyId, data.TargetDescription),
                                                      new PropertyAssignment(Association.FKPropertyNameDomainPropertyId, data.ForeignKey),
                                                      new PropertyAssignment(Association.SourceRoleDomainPropertyId, ConvertRole(data.SourceRole)), 
                                                      new PropertyAssignment(Association.TargetRoleDomainPropertyId, ConvertRole(data.TargetRole)), 
                                                      new PropertyAssignment(BidirectionalAssociation.SourcePropertyNameDomainPropertyId, data.SourcePropertyName),
                                                      new PropertyAssignment(BidirectionalAssociation.SourceSummaryDomainPropertyId, data.SourceSummary),
                                                      new PropertyAssignment(BidirectionalAssociation.SourceDescriptionDomainPropertyId, data.SourceDescription),
                                                   });
            AssociationChangedRules.SetEndpointRoles(element);
         }
      }
Пример #19
0
 private void ConfigureNewAssociation(BidirectionalAssociation element)
 {
     SetInitialMultiplicity(element);
     SetTargetPropertyName(element);
     SetSourcePropertyName(element);
 }
Пример #20
0
        public override void ElementPropertyChanged(ElementPropertyChangedEventArgs e)
        {
            base.ElementPropertyChanged(e);

            Association element = (Association)e.ModelElement;

            if (element.IsDeleted)
            {
                return;
            }

            Store       store   = element.Store;
            Transaction current = store.TransactionManager.CurrentTransaction;

            if (current.IsSerializing || ModelRoot.BatchUpdating)
            {
                return;
            }

            if (Equals(e.NewValue, e.OldValue))
            {
                return;
            }

            List <string>            errorMessages            = EFCoreValidator.GetErrors(element).ToList();
            BidirectionalAssociation bidirectionalAssociation = element as BidirectionalAssociation;

            switch (e.DomainProperty.Name)
            {
            case "FKPropertyName":
            {
                string fkPropertyName  = e.NewValue?.ToString();
                bool   fkPropertyError = false;

                // these can be multiples, separated by a comma
                string[] priorForeignKeyPropertyNames = e.OldValue?.ToString().Split(',').Select(n => n.Trim()).ToArray() ?? new string[0];

                IEnumerable <ModelAttribute> priorForeignKeyModelAttributes = string.IsNullOrEmpty(e.OldValue?.ToString())
                                                                                  ? Array.Empty <ModelAttribute>()
                                                                                  : priorForeignKeyPropertyNames.Select(oldValue => element.Dependent.Attributes.FirstOrDefault(a => a.Name == oldValue))
                                                                              .ToArray();

                if (!string.IsNullOrEmpty(fkPropertyName))
                {
                    string tag = $"({element.Source.Name}:{element.Target.Name})";

                    if (element.Dependent == null)
                    {
                        errorMessages.Add($"{tag} can't have foreign keys defined; no dependent role found");
                        break;
                    }

                    string[] foreignKeyPropertyNames = element.GetForeignKeyPropertyNames();
                    int      propertyCount           = foreignKeyPropertyNames.Length;
                    int      identityCount           = element.Principal.AllIdentityAttributes.Count();

                    if (propertyCount != identityCount)
                    {
                        errorMessages.Add($"{tag} foreign key must have zero or {identityCount} {(identityCount == 1 ? "property" : "properties")} defined, since "
                                          + $"{element.Principal.Name} has {identityCount} identity properties; found {propertyCount} instead");
                        fkPropertyError = true;
                    }

                    // validate names
                    foreach (string propertyName in foreignKeyPropertyNames)
                    {
                        if (!CodeGenerator.IsValidLanguageIndependentIdentifier(propertyName))
                        {
                            errorMessages.Add($"{tag} FK property name '{propertyName}' isn't a valid .NET identifier");
                            fkPropertyError = true;
                        }

                        if (element.Dependent.AllAttributes.Except(element.Dependent.Attributes).Any(a => a.Name == propertyName))
                        {
                            errorMessages.Add($"{tag} FK property name '{propertyName}' is used in a base class of {element.Dependent.Name}");
                            fkPropertyError = true;
                        }
                    }

                    if (!fkPropertyError)
                    {
                        // remove any flags and locks on the attributes that were foreign keys
                        foreach (ModelAttribute modelAttribute in priorForeignKeyModelAttributes)
                        {
                            modelAttribute.SetLocks(Locks.None);
                            modelAttribute.Summary      = null;
                            modelAttribute.IsForeignKey = false;
                            modelAttribute.RedrawItem();
                        }

                        element.EnsureForeignKeyAttributes();

                        IEnumerable <ModelAttribute> currentForeignKeyModelAttributes = foreignKeyPropertyNames.Select(newValue => element.Dependent.Attributes.FirstOrDefault(a => a.Name == newValue));

                        // add delete flags and locks to the attributes that are now foreign keys
                        foreach (ModelAttribute modelAttribute in currentForeignKeyModelAttributes)
                        {
                            modelAttribute.SetLocks(Locks.None);
                            modelAttribute.Summary = $"Foreign key for {element.GetDisplayText()}";
                            modelAttribute.SetLocks(Locks.Delete);
                            modelAttribute.IsForeignKey = true;
                            modelAttribute.RedrawItem();
                        }
                    }
                }
                else
                {
                    // foreign key was removed
                    // remove locks
                    foreach (ModelAttribute modelAttribute in priorForeignKeyModelAttributes)
                    {
                        modelAttribute.SetLocks(Locks.None);
                        modelAttribute.Summary      = null;
                        modelAttribute.IsForeignKey = false;
                    }
                }
            }

            break;

            case "SourceCustomAttributes":

                if (bidirectionalAssociation != null && !string.IsNullOrWhiteSpace(bidirectionalAssociation.SourceCustomAttributes))
                {
                    bidirectionalAssociation.SourceCustomAttributes = $"[{bidirectionalAssociation.SourceCustomAttributes.Trim('[', ']')}]";
                    CheckSourceForDisplayText(bidirectionalAssociation);
                }

                break;

            case "SourceDisplayText":

                if (bidirectionalAssociation != null)
                {
                    CheckSourceForDisplayText(bidirectionalAssociation);
                }

                break;

            case "SourceMultiplicity":
                Multiplicity sourceMultiplicity = (Multiplicity)e.NewValue;

                // change unidirectional source cardinality
                // if target is dependent
                //    source cardinality is 0..1 or 1
                if (element.Target.IsDependentType && sourceMultiplicity == Multiplicity.ZeroMany)
                {
                    errorMessages.Add($"Can't have a 0..* association from {element.Target.Name} to dependent type {element.Source.Name}");

                    break;
                }

                if ((sourceMultiplicity == Multiplicity.One && element.TargetMultiplicity == Multiplicity.One) ||
                    (sourceMultiplicity == Multiplicity.ZeroOne && element.TargetMultiplicity == Multiplicity.ZeroOne))
                {
                    if (element.SourceRole != EndpointRole.NotSet)
                    {
                        element.SourceRole = EndpointRole.NotSet;
                    }

                    if (element.TargetRole != EndpointRole.NotSet)
                    {
                        element.TargetRole = EndpointRole.NotSet;
                    }
                }
                else
                {
                    SetEndpointRoles(element);
                }

                // cascade delete behavior could now be illegal. Reset to default
                element.SourceDeleteAction = DeleteAction.Default;
                element.TargetDeleteAction = DeleteAction.Default;

                break;

            case "SourcePropertyName":
                string sourcePropertyNameErrorMessage = ValidateAssociationIdentifier(element, element.Target, (string)e.NewValue);

                if (EFModelDiagram.IsDropping && sourcePropertyNameErrorMessage != null)
                {
                    element.Delete();
                }
                else
                {
                    errorMessages.Add(sourcePropertyNameErrorMessage);
                }

                break;

            case "SourceRole":

                if (element.Source.IsDependentType)
                {
                    element.SourceRole = EndpointRole.Dependent;
                    element.TargetRole = EndpointRole.Principal;
                }
                else if (!SetEndpointRoles(element))
                {
                    if (element.SourceRole == EndpointRole.Dependent && element.TargetRole != EndpointRole.Principal)
                    {
                        element.TargetRole = EndpointRole.Principal;
                    }
                    else if (element.SourceRole == EndpointRole.Principal && element.TargetRole != EndpointRole.Dependent)
                    {
                        element.TargetRole = EndpointRole.Dependent;
                    }
                }

                break;

            case "TargetCustomAttributes":

                if (!string.IsNullOrWhiteSpace(element.TargetCustomAttributes))
                {
                    element.TargetCustomAttributes = $"[{element.TargetCustomAttributes.Trim('[', ']')}]";
                    CheckTargetForDisplayText(element);
                }

                break;

            case "TargetDisplayText":

                CheckTargetForDisplayText(element);

                break;

            case "TargetMultiplicity":
                Multiplicity newTargetMultiplicity = (Multiplicity)e.NewValue;

                // change unidirectional target cardinality
                // if target is dependent
                //    target cardinality must be 0..1 or 1
                if (element.Target.IsDependentType && newTargetMultiplicity == Multiplicity.ZeroMany)
                {
                    errorMessages.Add($"Can't have a 0..* association from {element.Source.Name} to dependent type {element.Target.Name}");

                    break;
                }

                if ((element.SourceMultiplicity == Multiplicity.One && newTargetMultiplicity == Multiplicity.One) ||
                    (element.SourceMultiplicity == Multiplicity.ZeroOne && newTargetMultiplicity == Multiplicity.ZeroOne))
                {
                    if (element.SourceRole != EndpointRole.NotSet)
                    {
                        element.SourceRole = EndpointRole.NotSet;
                    }

                    if (element.TargetRole != EndpointRole.NotSet)
                    {
                        element.TargetRole = EndpointRole.NotSet;
                    }
                }
                else
                {
                    SetEndpointRoles(element);
                }

                // cascade delete behavior could now be illegal. Reset to default
                element.SourceDeleteAction = DeleteAction.Default;
                element.TargetDeleteAction = DeleteAction.Default;

                break;

            case "TargetPropertyName":

                // if we're creating an association via drag/drop, it's possible the existing property name
                // is the same as the default property name. The default doesn't get created until the transaction is
                // committed, so the drop's action will cause a name clash. Remove the clashing property, but
                // only if drag/drop.

                string targetPropertyNameErrorMessage = ValidateAssociationIdentifier(element, element.Source, (string)e.NewValue);

                if (EFModelDiagram.IsDropping && targetPropertyNameErrorMessage != null)
                {
                    element.Delete();
                }
                else
                {
                    errorMessages.Add(targetPropertyNameErrorMessage);
                }

                break;

            case "TargetRole":

                if (element.Target.IsDependentType)
                {
                    element.SourceRole = EndpointRole.Principal;
                    element.TargetRole = EndpointRole.Dependent;
                }
                else if (!SetEndpointRoles(element))
                {
                    if (element.TargetRole == EndpointRole.Dependent && element.SourceRole != EndpointRole.Principal)
                    {
                        element.SourceRole = EndpointRole.Principal;
                    }
                    else if (element.TargetRole == EndpointRole.Principal && element.SourceRole != EndpointRole.Dependent)
                    {
                        element.SourceRole = EndpointRole.Dependent;
                    }
                }

                break;
            }

            errorMessages = errorMessages.Where(m => m != null).ToList();

            if (errorMessages.Any())
            {
                current.Rollback();
                ErrorDisplay.Show(string.Join("\n", errorMessages));
            }
        }
Пример #21
0
        /// <inheritdoc />
        public override void ElementPropertyChanged(ElementPropertyChangedEventArgs e)
        {
            base.ElementPropertyChanged(e);

            Association element = (Association)e.ModelElement;

            if (element.IsDeleted)
            {
                return;
            }

            Store       store     = element.Store;
            ModelRoot   modelRoot = store.ModelRoot();
            Transaction current   = store.TransactionManager.CurrentTransaction;

            if (current.IsSerializing || ModelRoot.BatchUpdating)
            {
                return;
            }

            if (Equals(e.NewValue, e.OldValue))
            {
                return;
            }

            List <string>            errorMessages            = EFCoreValidator.GetErrors(element).ToList();
            BidirectionalAssociation bidirectionalAssociation = element as BidirectionalAssociation;

            using (Transaction inner = store.TransactionManager.BeginTransaction("Association ElementPropertyChanged"))
            {
                bool doForeignKeyFixup = false;

                switch (e.DomainProperty.Name)
                {
                case "FKPropertyName":
                {
                    if (store.ModelRoot().EntityFrameworkVersion == EFVersion.EF6 &&
                        element.SourceMultiplicity != Multiplicity.ZeroMany &&
                        element.TargetMultiplicity != Multiplicity.ZeroMany)
                    {
                        element.FKPropertyName = null;
                        doForeignKeyFixup      = true;
                    }
                    else
                    {
                        ValidateForeignKeyNames(element, errorMessages);
                    }

                    if (!errorMessages.Any())
                    {
                        doForeignKeyFixup = true;
                    }

                    break;
                }

                case "SourceCustomAttributes":
                {
                    if (bidirectionalAssociation != null && !string.IsNullOrWhiteSpace(bidirectionalAssociation.SourceCustomAttributes))
                    {
                        bidirectionalAssociation.SourceCustomAttributes = $"[{bidirectionalAssociation.SourceCustomAttributes.Trim('[', ']')}]";
                        CheckSourceForDisplayText(bidirectionalAssociation);
                    }

                    break;
                }

                case "SourceDisplayText":
                {
                    if (bidirectionalAssociation != null)
                    {
                        CheckSourceForDisplayText(bidirectionalAssociation);
                    }

                    break;
                }

                case "SourceMultiplicity":
                {
                    if (!ValidateMultiplicity(element, modelRoot, errorMessages, store, ref doForeignKeyFixup))
                    {
                        break;
                    }

                    Multiplicity priorSourceMultiplicity = (Multiplicity)e.OldValue;

                    if (((priorSourceMultiplicity == Multiplicity.ZeroOne || priorSourceMultiplicity == Multiplicity.ZeroMany) && element.SourceMultiplicity == Multiplicity.One) ||
                        ((element.SourceMultiplicity == Multiplicity.ZeroOne || element.SourceMultiplicity == Multiplicity.ZeroMany) && priorSourceMultiplicity == Multiplicity.One))
                    {
                        doForeignKeyFixup = true;
                    }

                    string defaultSourcePropertyName =
                        priorSourceMultiplicity == Multiplicity.ZeroMany && ModelRoot.PluralizationService?.IsSingular(element.Source.Name) == true
                                          ? ModelRoot.PluralizationService.Pluralize(element.Source.Name)
                                          : element.Source.Name;

                    if (element is BidirectionalAssociation bidirectional && bidirectional.SourcePropertyName == defaultSourcePropertyName)
                    {
                        bidirectional.SourcePropertyName = element.SourceMultiplicity == Multiplicity.ZeroMany && ModelRoot.PluralizationService?.IsSingular(element.Source.Name) == true
                                                           ? ModelRoot.PluralizationService.Pluralize(element.Source.Name)
                                                           : element.Source.Name;
                    }

                    break;
                }

                case "SourcePropertyName":
                {
                    string sourcePropertyNameErrorMessage = ValidateAssociationIdentifier(element, element.Target, (string)e.NewValue);

                    if (EFModelDiagram.IsDroppingExternal && sourcePropertyNameErrorMessage != null)
                    {
                        element.Delete();
                    }
                    else
                    {
                        errorMessages.Add(sourcePropertyNameErrorMessage);
                    }

                    break;
                }

                case "SourceRole":
                {
                    if (element.SourceRole == EndpointRole.NotApplicable)
                    {
                        element.SourceRole = EndpointRole.NotSet;
                    }

                    //if (element.Source.IsDependentType)
                    //{
                    //   element.SourceRole = EndpointRole.Dependent;
                    //   element.TargetRole = EndpointRole.Principal;
                    //}
                    //else
                    if (!SetEndpointRoles(element))
                    {
                        if (element.SourceRole == EndpointRole.Dependent && element.TargetRole != EndpointRole.Principal)
                        {
                            element.TargetRole = EndpointRole.Principal;
                        }
                        else if (element.SourceRole == EndpointRole.Principal && element.TargetRole != EndpointRole.Dependent)
                        {
                            element.TargetRole = EndpointRole.Dependent;
                        }
                    }

                    doForeignKeyFixup = true;

                    break;
                }

                case "TargetCustomAttributes":
                {
                    if (!string.IsNullOrWhiteSpace(element.TargetCustomAttributes))
                    {
                        element.TargetCustomAttributes = $"[{element.TargetCustomAttributes.Trim('[', ']')}]";
                        CheckTargetForDisplayText(element);
                    }

                    break;
                }

                case "TargetDisplayText":
                {
                    CheckTargetForDisplayText(element);

                    break;
                }

                case "TargetMultiplicity":
                {
                    if (!ValidateMultiplicity(element, modelRoot, errorMessages, store, ref doForeignKeyFixup))
                    {
                        break;
                    }

                    Multiplicity priorTargetMultiplicity = (Multiplicity)e.OldValue;

                    if (((priorTargetMultiplicity == Multiplicity.ZeroOne || priorTargetMultiplicity == Multiplicity.ZeroMany) && element.TargetMultiplicity == Multiplicity.One) ||
                        ((element.TargetMultiplicity == Multiplicity.ZeroOne || element.TargetMultiplicity == Multiplicity.ZeroMany) && priorTargetMultiplicity == Multiplicity.One))
                    {
                        doForeignKeyFixup = true;
                    }

                    string defaultTargetPropertyName =
                        priorTargetMultiplicity == Multiplicity.ZeroMany && ModelRoot.PluralizationService?.IsSingular(element.Target.Name) == true
                        ? ModelRoot.PluralizationService.Pluralize(element.Target.Name)
                        : element.Target.Name;

                    if (element.TargetPropertyName == defaultTargetPropertyName)
                    {
                        element.TargetPropertyName = element.TargetMultiplicity == Multiplicity.ZeroMany && ModelRoot.PluralizationService?.IsSingular(element.Target.Name) == true
                                             ? ModelRoot.PluralizationService.Pluralize(element.Target.Name)
                                             : element.Target.Name;
                    }
                    break;
                }

                case "TargetPropertyName":
                {
                    // if we're creating an association via drag/drop, it's possible the existing property name
                    // is the same as the default property name. The default doesn't get created until the transaction is
                    // committed, so the drop's action will cause a name clash. Remove the clashing property, but
                    // only if drag/drop.

                    string targetPropertyNameErrorMessage = ValidateAssociationIdentifier(element, element.Source, (string)e.NewValue);

                    if (EFModelDiagram.IsDroppingExternal && targetPropertyNameErrorMessage != null)
                    {
                        element.Delete();
                    }
                    else
                    {
                        errorMessages.Add(targetPropertyNameErrorMessage);
                    }

                    break;
                }

                case "TargetRole":
                {
                    if (element.TargetRole == EndpointRole.NotApplicable)
                    {
                        element.TargetRole = EndpointRole.NotSet;
                    }

                    //if (element.Target.IsDependentType && (element.SourceRole != EndpointRole.Principal || element.TargetRole != EndpointRole.Dependent))
                    //{
                    //   element.SourceRole = EndpointRole.Principal;
                    //   element.TargetRole = EndpointRole.Dependent;
                    //   doForeignKeyFixup = true;
                    //}
                    //else
                    if (!SetEndpointRoles(element))
                    {
                        if (element.TargetRole == EndpointRole.Dependent && element.SourceRole != EndpointRole.Principal)
                        {
                            element.SourceRole = EndpointRole.Principal;
                            doForeignKeyFixup  = true;
                        }
                        else if (element.TargetRole == EndpointRole.Principal && element.SourceRole != EndpointRole.Dependent)
                        {
                            element.SourceRole = EndpointRole.Dependent;
                            doForeignKeyFixup  = true;
                        }
                    }

                    break;
                }
                }

                if (doForeignKeyFixup)
                {
                    FixupForeignKeys(element);
                }

                inner.Commit();
                element.RedrawItem();
            }

            errorMessages = errorMessages.Where(m => m != null).ToList();

            if (errorMessages.Any())
            {
                current.Rollback();
                ErrorDisplay.Show(store, string.Join("\n", errorMessages));
            }
        }