From d8615471242d2519ddd1f1c4eb54a9d68ee8b6d1 Mon Sep 17 00:00:00 2001 From: Eirik Bjornset Date: Sat, 2 Nov 2024 17:11:19 +0100 Subject: [PATCH] Added support for generating many to many relations in mermaid-er-diagram-from-efcore (#133) --- .../releasenotes/yyyy-MM-dd-v-x.y.z.md | 3 +- .../ErDiagram/ErDiagramEntity.cs | 28 +++++++++++++++++-- .../ErDiagram/ErDiagramRelationship.cs | 7 ++++- .../ErDiagramStructureBuilderByReflection.cs | 7 ++++- .../GeneratingErRelationships.feature | 8 +++--- 5 files changed, 44 insertions(+), 9 deletions(-) diff --git a/docs/templates/releasenotes/yyyy-MM-dd-v-x.y.z.md b/docs/templates/releasenotes/yyyy-MM-dd-v-x.y.z.md index 918fa64f..ce98f184 100644 --- a/docs/templates/releasenotes/yyyy-MM-dd-v-x.y.z.md +++ b/docs/templates/releasenotes/yyyy-MM-dd-v-x.y.z.md @@ -4,7 +4,8 @@ ### Improvements in this version ## Prerelease 2 -- Added support for generating many to many association in `mermaid-class-diagram-from-csharp`. +- Added support for generating many to many associations in `mermaid-class-diagram-from-csharp`. +- Added support for generating many to many relations in `mermaid-er-diagram-from-csharp`. ## Prerelease 1 (2024-10-29) - Fixed an issue where `mermaid-er-diagram-from-efcore` would fail when an input assebly referenced Asp.Net Core. - Ie the .csproj file contained `` or `` or referenced such an assembly. diff --git a/src/DryGen.MermaidFromCSharp/ErDiagram/ErDiagramEntity.cs b/src/DryGen.MermaidFromCSharp/ErDiagram/ErDiagramEntity.cs index 938aba9b..8e1b5741 100644 --- a/src/DryGen.MermaidFromCSharp/ErDiagram/ErDiagramEntity.cs +++ b/src/DryGen.MermaidFromCSharp/ErDiagram/ErDiagramEntity.cs @@ -34,8 +34,13 @@ public void AddAttribute(ErDiagramAttribute attribute) public void AddRelationship(ErDiagramEntity to, ErDiagramRelationshipCardinality fromCardinality, ErDiagramRelationshipCardinality toCardinality, string label, string propertyName, bool isIdentifying = false) { - var relationShip = new ErDiagramRelationship(to, fromCardinality, toCardinality, label, propertyName, isIdentifying); - relationships.Add(relationShip); + var relationship = new ErDiagramRelationship(to, fromCardinality, toCardinality, label, propertyName, isIdentifying); + relationships.Add(relationship); + } + + public void RemoveRelationship(ErDiagramRelationship relationship) + { + relationships.Remove(relationship); } public void RemoveBidirectionalRelationshipDuplicates() @@ -47,6 +52,25 @@ public void RemoveBidirectionalRelationshipDuplicates() || r.To.GetRelationships().Any(x => x.To == this))); } +public void MergeTwoOneToManyIntoOneMayToMany() + { + bool wasModified; + do + { + // Must use an outer loop since a self referencing many to many will modify the relationships collection and the enumeration will crash + wasModified = false; + foreach (var relationship in relationships.Where(x => x.FromCardinality == ErDiagramRelationshipCardinality.ExactlyOne && x.ToCardinality == ErDiagramRelationshipCardinality.ZeroOrMore && ! x.IsIdenifying)) { + var backRelationship = relationship.To.Relationships.FirstOrDefault(x => x.To == this && x.FromCardinality == ErDiagramRelationshipCardinality.ExactlyOne && x.ToCardinality == ErDiagramRelationshipCardinality.ZeroOrMore && ! x.IsIdenifying && x != relationship); + if (backRelationship == null) { + continue; + } + relationship.MergeAsManyToManyWith(backRelationship); + wasModified = true; + break; + } + } while (wasModified); + } + protected override bool IsRelatedTo(IDiagramType type) { var result = relationships.Exists(x => x.To.Type == type.Type); diff --git a/src/DryGen.MermaidFromCSharp/ErDiagram/ErDiagramRelationship.cs b/src/DryGen.MermaidFromCSharp/ErDiagram/ErDiagramRelationship.cs index 84568af7..aaef10a2 100644 --- a/src/DryGen.MermaidFromCSharp/ErDiagram/ErDiagramRelationship.cs +++ b/src/DryGen.MermaidFromCSharp/ErDiagram/ErDiagramRelationship.cs @@ -19,9 +19,14 @@ public ErDiagramRelationship( } public ErDiagramEntity To { get; } - public ErDiagramRelationshipCardinality FromCardinality { get; } + public ErDiagramRelationshipCardinality FromCardinality { get; private set; } public ErDiagramRelationshipCardinality ToCardinality { get; } public string Label { get; } internal string PropertyName { get; } public bool IsIdenifying { get; } + + public void MergeAsManyToManyWith(ErDiagramRelationship backRelationship) { + FromCardinality = ErDiagramRelationshipCardinality.ZeroOrMore; + To.RemoveRelationship(backRelationship); + } } \ No newline at end of file diff --git a/src/DryGen.MermaidFromCSharp/ErDiagram/ErDiagramStructureBuilderByReflection.cs b/src/DryGen.MermaidFromCSharp/ErDiagram/ErDiagramStructureBuilderByReflection.cs index ef3f1fda..29ad3ae2 100644 --- a/src/DryGen.MermaidFromCSharp/ErDiagram/ErDiagramStructureBuilderByReflection.cs +++ b/src/DryGen.MermaidFromCSharp/ErDiagram/ErDiagramStructureBuilderByReflection.cs @@ -36,7 +36,8 @@ private static void GeneratieErStructure(IList entities, IReadO var genericArgumentPropertyType = propertyType.GetGenericArguments()[0]; if (entityLookup.TryGetValue(genericArgumentPropertyType, out var toEntity)) { - entity.AddRelationship(toEntity, ErDiagramRelationshipCardinality.ExactlyOne, ErDiagramRelationshipCardinality.ZeroOrMore, string.Empty, property.Name); + var label = property.Name.Contains(toEntity.Name) ? string.Empty : property.Name.ToNormalizedRelationshipLabel(); + entity.AddRelationship(toEntity, ErDiagramRelationshipCardinality.ExactlyOne, ErDiagramRelationshipCardinality.ZeroOrMore, label, property.Name); } } else if (property.IsErDiagramAttributePropertyType()) @@ -56,6 +57,10 @@ private static void GeneratieErStructure(IList entities, IReadO { entity.RemoveBidirectionalRelationshipDuplicates(); } + foreach (var entity in entities) + { + entity.MergeTwoOneToManyIntoOneMayToMany(); + } enumEntities.AppendToEntities(entities); } } \ No newline at end of file diff --git a/src/develop/DryGen.UTests/Features/Mermaid/FromCSharpAndEfCore/ErDiagram/GeneratingErRelationships.feature b/src/develop/DryGen.UTests/Features/Mermaid/FromCSharpAndEfCore/ErDiagram/GeneratingErRelationships.feature index b4404f5f..b7324a82 100644 --- a/src/develop/DryGen.UTests/Features/Mermaid/FromCSharpAndEfCore/ErDiagram/GeneratingErRelationships.feature +++ b/src/develop/DryGen.UTests/Features/Mermaid/FromCSharpAndEfCore/ErDiagram/GeneratingErRelationships.feature @@ -366,7 +366,7 @@ Scenario: Generates many to many relationship with only one property in the key """ Examples: | Structure builder | - #| Reflection | + | Reflection | | EfCore | Scenario: Generates many to many relationship with several properties in the key @@ -412,7 +412,7 @@ Scenario: Generates many to many relationship with several properties in the key """ Examples: | Structure builder | - #| Reflection | + | Reflection | | EfCore | Scenario: Generates self referencing many to many relationship with only one property in the key @@ -444,7 +444,7 @@ Scenario: Generates self referencing many to many relationship with only one pro """ Examples: | Structure builder | - #| Reflection | + | Reflection | | EfCore | Scenario: Generates self referencing many to many relationship with several properties in the key @@ -482,5 +482,5 @@ Scenario: Generates self referencing many to many relationship with several prop """ Examples: | Structure builder | - #| Reflection | + | Reflection | | EfCore |