diff --git a/changelog.txt b/changelog.txt
index d38534a49..75792a8d4 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,10 @@
+4.1.2
+ - Added association classes to model for EFCore >= 5
+ - Added table comments for EFCore >= 5 (generation of [Comment] attribute on class)
+
+4.0.0
+ - Added EFCore 6 support
+
3.1.0
- Fix generalizations in assembly import
- Add DbContextFactory generation on request
diff --git a/src/Dsl/CustomCode/Gestures/ClassDragMouseAction.cs b/src/Dsl/CustomCode/Gestures/ClassDragMouseAction.cs
new file mode 100644
index 000000000..a384828ed
--- /dev/null
+++ b/src/Dsl/CustomCode/Gestures/ClassDragMouseAction.cs
@@ -0,0 +1,336 @@
+//using System.Collections.Generic;
+//using System.Diagnostics;
+//using System.Linq;
+//using System.Windows.Forms;
+
+//using Microsoft.VisualStudio.Modeling.Diagrams;
+
+//namespace Sawczyn.EFDesigner.EFModel
+//{
+// public class ClassDragMouseAction : MouseAction
+// {
+// private readonly ClassShape _classShape;
+// private readonly ModelClass _modelClass;
+
+// public ClassDragMouseAction(ClassShape classShape) : base(classShape.Diagram)
+// {
+// _classShape = classShape;
+// _modelClass = (ModelClass)classShape.ModelElement;
+// }
+
+// ///
+// /// Called when a MouseMove event has been dispatched to this MouseAction.
+// ///
+// /// A DiagramMouseEventArgs that contains event data.
+// /// To modify the cursor, override GetCursor.
+// ///
+// /// To draw feedback for this MouseAction, override DoPaintFeedback.
+// ///
+// protected override void OnMouseMove(DiagramMouseEventArgs e)
+// {
+// Debug.WriteLine("OnMouseMove 0");
+// base.OnMouseMove(e);
+// Debug.WriteLine("OnMouseMove 1");
+// }
+
+// ///
+// /// Called when a MouseDown event has been dispatched to this MouseAction.
+// ///
+// /// A DiagramMouseEventArgs that contains event data.
+// protected override void OnMouseDown(DiagramMouseEventArgs e)
+// {
+// Debug.WriteLine("OnMouseDown 0");
+// base.OnMouseDown(e);
+// Debug.WriteLine("OnMouseDown 1");
+// }
+
+// ///
+// /// Called when this MouseAction's drag operation has been canceled.
+// ///
+// /// A MouseActionEventArgs that contains event data.
+// ///
+// /// Set e.ActionRequest to ActionRequest.CompleteAction to complete the
+// /// MouseAction and deactivate it.
+// ///
+// ///
+// /// Set e.ActionRequest to ActionRequest.CancelAction to cancel the
+// /// MouseAction and deactivate it.
+// ///
+// ///
+// /// Set e.ActionRequest to ActionRequest.ContinueAction to keep the
+// /// MouseAction active. This will place the MouseAction in the
+// /// hovering state.
+// ///
+// protected override void OnDragCanceled(MouseActionEventArgs e)
+// {
+// Debug.WriteLine("OnDragCanceled 0");
+// base.OnDragCanceled(e);
+// Debug.WriteLine("OnDragCanceled 1");
+// }
+
+// ///
+// /// Called when this MouseAction has entered the drag/click-pending state.
+// ///
+// /// A MouseActionEventArgs that contains event data.
+// ///
+// /// The drag/click-pending state begins when a MouseDown event occurs while
+// /// the MouseAction is in a hovering state or while it is inactive.
+// ///
+// protected override void OnDragPendingBegun(MouseActionEventArgs e)
+// {
+// Debug.WriteLine("OnDragPendingBegun 0");
+// base.OnDragPendingBegun(e);
+// Debug.WriteLine("OnDragPendingBegun 1");
+// }
+
+// ///
+// /// Called when this MouseAction has exited the drag/click-pending state.
+// ///
+// /// A MouseActionEventArgs that contains event data.
+// ///
+// /// The drag/click-pending state ends when the criteria for dragging has been
+// /// satisfied, or when a MouseUp has been received before dragging could begin
+// /// (in which case the user has clicked), or when a Complete or Cancel event
+// /// has been received.
+// ///
+// protected override void OnDragPendingEnded(MouseActionEventArgs e)
+// {
+// Debug.WriteLine("OnDragPendingEnded 0");
+// base.OnDragPendingEnded(e);
+// Debug.WriteLine("OnDragPendingEnded 1");
+// }
+
+// /// Called when this MouseAction has been activated.
+// /// A DiagramEventArgs that contains event data.
+// protected override void OnMouseActionActivated(DiagramEventArgs e)
+// {
+// Debug.WriteLine("OnMouseActionActivated 0");
+// base.OnMouseActionActivated(e);
+// Debug.WriteLine("OnMouseActionActivated 1");
+// }
+
+// ///
+// /// Called when the MouseAction has been canceled and is ready to be deactivated.
+// ///
+// /// A DiagramEventArgs that contains event data.
+// protected override void OnMouseActionCanceled(DiagramEventArgs e)
+// {
+// Debug.WriteLine("OnMouseActionCanceled 0");
+// base.OnMouseActionCanceled(e);
+// Debug.WriteLine("OnMouseActionCanceled 1");
+// }
+
+// ///
+// /// Called when the MouseAction has completed and is ready to be deactivated.
+// ///
+// /// A DiagramEventArgs that contains event data.
+// protected override void OnMouseActionCompleted(DiagramEventArgs e)
+// {
+// Debug.WriteLine("OnMouseActionCompleted 0");
+// base.OnMouseActionCompleted(e);
+// Debug.WriteLine("OnMouseActionCompleted 1");
+// }
+
+// /// Called when this MouseAction has been deactivated.
+// /// A DiagramEventArgs that contains event data.
+// protected override void OnMouseActionDeactivated(DiagramEventArgs e)
+// {
+// Debug.WriteLine("OnMouseActionDeactivated 0");
+// base.OnMouseActionDeactivated(e);
+// Debug.WriteLine("OnMouseActionDeactivated 1");
+// }
+
+// ///
+// /// Called when a MouseUp event has been dispatched to this MouseAction.
+// ///
+// /// A DiagramMouseEventArgs that contains event data.
+// ///
+// /// If your intent is to respond to a MouseDown + MouseUp
+// /// combination that does not include dragging, override the
+// /// OnClicked method instead.
+// /// (A MouseMove may occur between MouseDown and MouseUp that does
+// /// not exceed a drag delta and therefore does not start dragging.)
+// ///
+// ///
+// /// If your intent is to respond to a MouseDown + Drag + MouseUp
+// /// combination, override the OnDragCompleted method instead.
+// /// (Drag occurs when the MouseMove exceeds a drag delta.)
+// ///
+// ///
+// /// If your intent is to respond to a double-click event, override
+// /// the OnDoubleClick method instead.
+// ///
+// ///
+// /// If your intent is to respond to the right-click event (perhaps
+// /// to prevent the context menu from appearing), override the
+// /// OnContextMenuRequested method instead.
+// ///
+// protected override void OnMouseUp(DiagramMouseEventArgs e)
+// {
+// Debug.WriteLine("OnMouseUp 0");
+// base.OnMouseUp(e);
+// Debug.WriteLine("OnMouseUp 1");
+// List candidates = _classShape.GetBidirectionalConnectorsUnderShape();
+
+// if (candidates.Any())
+// {
+// Debug.WriteLine("OnMouseUp 2");
+
+// foreach (BidirectionalConnector candidate in candidates)
+// {
+// Debug.WriteLine("OnMouseUp 3");
+// BidirectionalAssociation association = ((BidirectionalAssociation)candidate.ModelElement);
+
+// if (BooleanQuestionDisplay.Show(_classShape.Store, $"Make {_modelClass.Name} an association class for {association.GetDisplayText()}?") == true)
+// {
+// Debug.WriteLine("OnMouseUp 4");
+// _classShape.AddAssociationClass(candidate);
+// Complete(e.DiagramClientView);
+
+// Debug.WriteLine("OnMouseUp 5");
+
+// return;
+// }
+// }
+// }
+
+// Debug.WriteLine("OnMouseUp 6");
+// Cancel(e.DiagramClientView);
+// }
+
+// ///
+// /// Called when this MouseAction has entered the dragging state.
+// ///
+// /// A MouseActionEventArgs that contains event data.
+// ///
+// /// The dragging state begins when the criteria for dragging has been satisfied.
+// /// Typically, the mouse cursor must move beyond a drag delta.
+// ///
+// protected override void OnDraggingBegun(MouseActionEventArgs e)
+// {
+// Debug.WriteLine("OnDraggingBegun 0");
+// base.OnDraggingBegun(e);
+// Debug.WriteLine("OnDraggingBegun 1");
+// }
+
+// ///
+// /// Called when this MouseAction has exited the dragging state.
+// ///
+// /// A MouseActionEventArgs that contains event data.
+// ///
+// /// The dragging state ends when a MouseUp event has been received or when a
+// /// Complete or Cancel event has been received.
+// ///
+// protected override void OnDraggingEnded(MouseActionEventArgs e)
+// {
+// Debug.WriteLine("OnDraggingEnded 0");
+// base.OnDraggingEnded(e);
+// Debug.WriteLine("OnDraggingEnded 1");
+// }
+
+// ///
+// /// Called when this MouseAction's drag operation has completed.
+// ///
+// /// A MouseActionEventArgs that contains event data.
+// protected override void OnDragCompleted(MouseActionEventArgs e)
+// {
+// Debug.WriteLine("OnDragCompleted 0");
+// base.OnDragCompleted(e);
+// Debug.WriteLine("OnDragCompleted 1");
+
+// List candidates = _classShape.GetBidirectionalConnectorsUnderShape();
+
+// if (candidates.Any())
+// {
+// Debug.WriteLine("OnDragCompleted 2");
+
+// foreach (BidirectionalConnector candidate in candidates)
+// {
+// Debug.WriteLine("OnDragCompleted 3");
+// BidirectionalAssociation association = ((BidirectionalAssociation)candidate.ModelElement);
+
+// if (BooleanQuestionDisplay.Show(_classShape.Store, $"Make {_modelClass.Name} an association class for {association.GetDisplayText()}?") == true)
+// {
+// Debug.WriteLine("OnDragCompleted 4");
+// _classShape.AddAssociationClass(candidate);
+// e.ActionRequest = ActionRequest.CompleteAction;
+
+// Debug.WriteLine("OnDragCompleted 5");
+
+// return;
+// }
+// }
+// }
+
+// Debug.WriteLine("OnDragCompleted 6");
+// e.ActionRequest = ActionRequest.CancelAction;
+// }
+
+// ///
+// /// Gets the cursor to display at the specified mouse position.
+// ///
+// /// The existing cursor.
+// /// The DiagramClientView requesting the cursor.
+// /// The cursor position in world units relative to the top-left of the diagram.
+// /// The cursor to display at the specified mouse position.
+// ///
+// /// This method is called by the DiagramClientView if this MouseAction is active or
+// /// if it is the potential MouseAction.
+// ///
+// /// By default, this method returns the currentCursor.
+// public override Cursor GetCursor(Cursor currentCursor, DiagramClientView diagramClientView, PointD mousePosition)
+// {
+// return Cursors.SizeAll;
+// }
+
+// ///
+// /// Called by the DiagramClientView to paint the feedback for the MouseAction.
+// ///
+// /// A DiagramPaintEventArgs that contains event data.
+// public override void DoPaintFeedback(DiagramPaintEventArgs e)
+// {
+// Debug.WriteLine("DoPaintFeedback 0");
+// base.DoPaintFeedback(e);
+// Debug.WriteLine("DoPaintFeedback 1");
+
+// if (_modelClass != null && _modelClass.CanBecomeAssociationClass())
+// {
+// Debug.WriteLine("DoPaintFeedback 2");
+// List connectors = _classShape.GetBidirectionalConnectorsUnderShape();
+// HighlightedShapesCollection highlightedShapes = e.View.HighlightedShapes;
+
+// if (connectors.Any())
+// {
+// Debug.WriteLine("DoPaintFeedback 3");
+
+// if (!highlightedShapes.Contains(new DiagramItem(_classShape)))
+// {
+// Debug.WriteLine("DoPaintFeedback 4");
+// highlightedShapes.Add(new DiagramItem(_classShape));
+// _classShape.Invalidate();
+// }
+
+// foreach (BidirectionalConnector connector in connectors.Where(c => !highlightedShapes.Contains(new DiagramItem(c))))
+// {
+// Debug.WriteLine("DoPaintFeedback 5");
+// highlightedShapes.Add(new DiagramItem(connector));
+// connector.Invalidate();
+// }
+// }
+// else
+// {
+// Debug.WriteLine("DoPaintFeedback 6");
+// highlightedShapes.Remove(new DiagramItem(_classShape));
+// _classShape.Invalidate();
+
+// foreach (BidirectionalConnector connector in connectors)
+// {
+// Debug.WriteLine("DoPaintFeedback 7");
+// highlightedShapes.Remove(new DiagramItem(connector));
+// connector.Invalidate();
+// }
+// }
+// }
+// }
+// }
+//}
diff --git a/src/Dsl/CustomCode/Gestures/ClassShapeDragData.cs b/src/Dsl/CustomCode/Gestures/ClassShapeDragData.cs
index 64e0498d1..ba7da6148 100644
--- a/src/Dsl/CustomCode/Gestures/ClassShapeDragData.cs
+++ b/src/Dsl/CustomCode/Gestures/ClassShapeDragData.cs
@@ -66,37 +66,25 @@ public List GetBidirectionalConnectorsUnderShape(PointD
internal void HighlightActionableClassShapes(PointD mousePosition)
{
- List connectors = GetBidirectionalConnectorsUnderShape(mousePosition);
- HighlightedShapesCollection highlightedShapes = ClassShape.Diagram.ActiveDiagramView.DiagramClientView.HighlightedShapes;
-
- DiagramItem classShapeItem = new DiagramItem(ClassShape);
-
- if (highlightedShapes.Contains(classShapeItem))
- {
- highlightedShapes.Remove(classShapeItem);
- ClassShape.Invalidate();
- }
+ EFModelDiagram diagram = ((EFModelDiagram)ClassShape.Diagram);
+ diagram.Unhighlight(ClassShape);
foreach (BidirectionalConnector connector in priorHighlightedConnectors)
- {
- highlightedShapes.Remove(new DiagramItem(connector));
- connector.Invalidate();
- }
+ diagram.Unhighlight(connector);
priorHighlightedConnectors.Clear();
+ List connectors = GetBidirectionalConnectorsUnderShape(mousePosition);
+ HighlightedShapesCollection highlightedShapes = ClassShape.Diagram.ActiveDiagramView.DiagramClientView.HighlightedShapes;
+
if (connectors.Any())
{
priorHighlightedConnectors.AddRange(connectors);
- highlightedShapes.Add(classShapeItem);
- ClassShape.Invalidate();
+ diagram.Highlight(ClassShape);
foreach (BidirectionalConnector connector in connectors.Where(c => !highlightedShapes.Contains(new DiagramItem(c))))
- {
- highlightedShapes.Add(new DiagramItem(connector));
- connector.Invalidate();
- }
+ diagram.Highlight(connector);
}
}
}
diff --git a/src/Dsl/CustomCode/Partials/Association.cs b/src/Dsl/CustomCode/Partials/Association.cs
index 7634ed388..329849703 100644
--- a/src/Dsl/CustomCode/Partials/Association.cs
+++ b/src/Dsl/CustomCode/Partials/Association.cs
@@ -109,7 +109,7 @@ public ModelClass Dependent
///
public string[] GetForeignKeyPropertyNames()
{
- return FKPropertyName?.Split(',').Select(n => n.Trim()).ToArray() ?? new string[0];
+ return FKPropertyName?.Split(',').Select(n => n.Trim()).ToArray() ?? Array.Empty();
}
///
diff --git a/src/Dsl/CustomCode/Partials/ClassShape.cs b/src/Dsl/CustomCode/Partials/ClassShape.cs
index 573898c5e..02da614c1 100644
--- a/src/Dsl/CustomCode/Partials/ClassShape.cs
+++ b/src/Dsl/CustomCode/Partials/ClassShape.cs
@@ -14,7 +14,7 @@ namespace Sawczyn.EFDesigner.EFModel
{
public partial class ClassShape : IHighlightFromModelExplorer, ICompartmentShapeMouseTarget
{
- internal static ClassShapeDragData ShapeDragData;
+ internal static ClassShapeDragData ClassShapeDragData;
///
/// Initializes style set resources for this shape type
@@ -475,7 +475,7 @@ public override void OnMouseDown(DiagramMouseEventArgs e)
base.OnMouseDown(e);
if (((ModelClass)ModelElement).CanBecomeAssociationClass())
- ShapeDragData = new ClassShapeDragData(this, e.MousePosition);
+ ClassShapeDragData = new ClassShapeDragData(this, e.MousePosition);
}
///
@@ -487,7 +487,7 @@ public override void OnMouseDown(DiagramMouseEventArgs e)
///
public override Cursor GetCursor(Cursor currentCursor, DiagramClientView diagramClientView, PointD mousePosition)
{
- return ShapeDragData?.GetBidirectionalConnectorsUnderShape(mousePosition).Any() == true
+ return ClassShapeDragData?.GetBidirectionalConnectorsUnderShape(mousePosition).Any() == true
? Cursors.Hand
: base.GetCursor(currentCursor, diagramClientView, mousePosition);
}
diff --git a/src/Dsl/CustomCode/Partials/EFModelDiagram.cs b/src/Dsl/CustomCode/Partials/EFModelDiagram.cs
index 3559cf6b5..e4280f759 100644
--- a/src/Dsl/CustomCode/Partials/EFModelDiagram.cs
+++ b/src/Dsl/CustomCode/Partials/EFModelDiagram.cs
@@ -67,6 +67,20 @@ protected override bool ShouldAddShapeForElement(ModelElement element)
private bool ForceAddShape { get; set; }
+ public void Highlight(ShapeElement shape)
+ {
+ ShapeElement highlightShape = DetermineHighlightShape(shape);
+ if (highlightShape != null)
+ ActiveDiagramView.DiagramClientView.HighlightedShapes.Add(new DiagramItem(highlightShape));
+ }
+
+ public void Unhighlight(ShapeElement shape)
+ {
+ ShapeElement highlightShape = DetermineHighlightShape(shape);
+ if (highlightShape != null)
+ ActiveDiagramView.DiagramClientView.HighlightedShapes.Remove(new DiagramItem(highlightShape));
+ }
+
public override void OnDragOver(DiagramDragEventArgs diagramDragEventArgs)
{
base.OnDragOver(diagramDragEventArgs);
@@ -74,7 +88,12 @@ public override void OnDragOver(DiagramDragEventArgs diagramDragEventArgs)
if (diagramDragEventArgs.Handled)
return;
- bool isDroppingAssociationClass = ClassShape.ShapeDragData?.GetBidirectionalConnectorsUnderShape(diagramDragEventArgs.MousePosition).Any() == true;
+ List bidirectionalConnectorsUnderShape = ClassShape.ClassShapeDragData?.GetBidirectionalConnectorsUnderShape(diagramDragEventArgs.MousePosition);
+
+ foreach (BidirectionalConnector connector in bidirectionalConnectorsUnderShape)
+ Highlight(connector);
+
+ bool isDroppingAssociationClass = bidirectionalConnectorsUnderShape?.Any() == true;
if (isDroppingAssociationClass)
diagramDragEventArgs.Effect = DragDropEffects.Link;
@@ -100,7 +119,7 @@ private bool IsAcceptableDropItem(DiagramDragEventArgs diagramDragEventArgs)
&& filenames2.All(File.Exists))
|| (diagramDragEventArgs.Data.GetData("FileDrop") is string[] filenames3 && filenames3.All(File.Exists));
- bool isDroppingAssociationClass = ClassShape.ShapeDragData?.GetBidirectionalConnectorsUnderShape(diagramDragEventArgs.MousePosition).Any() == true;
+ bool isDroppingAssociationClass = ClassShape.ClassShapeDragData?.GetBidirectionalConnectorsUnderShape(diagramDragEventArgs.MousePosition).Any() == true;
return IsDroppingExternal || isDroppingAssociationClass;
}
@@ -139,7 +158,7 @@ public override void OnDragDrop(DiagramDragEventArgs diagramDragEventArgs)
ModelElement element = (diagramDragEventArgs.Data.GetData("Sawczyn.EFDesigner.EFModel.ModelClass") as ModelElement)
?? (diagramDragEventArgs.Data.GetData("Sawczyn.EFDesigner.EFModel.ModelEnum") as ModelElement);
- List candidates = ClassShape.ShapeDragData?.GetBidirectionalConnectorsUnderShape(diagramDragEventArgs.MousePosition);
+ List candidates = ClassShape.ClassShapeDragData?.GetBidirectionalConnectorsUnderShape(diagramDragEventArgs.MousePosition);
// are we creating an association class?
if (candidates?.Any() == true)
@@ -198,7 +217,7 @@ string BuildMessage(List newElements)
void MakeAssociationClass(List possibleConnectors)
{
- ModelClass modelClass = (ModelClass)ClassShape.ShapeDragData.ClassShape.ModelElement;
+ ModelClass modelClass = (ModelClass)ClassShape.ClassShapeDragData.ClassShape.ModelElement;
using (Transaction t = modelClass.Store.TransactionManager.BeginTransaction("Creating association class"))
{
@@ -209,7 +228,7 @@ void MakeAssociationClass(List possibleConnectors)
if (BooleanQuestionDisplay.Show(Store, $"Make {modelClass.Name} an association class for {association.GetDisplayText()}?") == true)
{
modelClass.ConvertToAssociationClass(association);
- ClassShape.ShapeDragData = null;
+ ClassShape.ClassShapeDragData = null;
break;
}
@@ -218,7 +237,7 @@ void MakeAssociationClass(List possibleConnectors)
t.Commit();
}
- ClassShape.ShapeDragData = null;
+ ClassShape.ClassShapeDragData = null;
}
void AddToDiagram(ModelElement elementToAdd, PointD atPosition)
@@ -348,7 +367,7 @@ public void DisableDiagramRules()
public override void OnMouseUp(DiagramMouseEventArgs e)
{
IsDroppingExternal = false;
- ClassShape.ShapeDragData = null;
+ ClassShape.ClassShapeDragData = null;
base.OnMouseUp(e);
}
diff --git a/src/Dsl/CustomCode/Partials/ModelClass.cs b/src/Dsl/CustomCode/Partials/ModelClass.cs
index 03cf8fb60..f1c10646c 100644
--- a/src/Dsl/CustomCode/Partials/ModelClass.cs
+++ b/src/Dsl/CustomCode/Partials/ModelClass.cs
@@ -522,7 +522,8 @@ internal void MoveAttribute(ModelAttribute attribute, ModelClass destination)
internal bool CanBecomeAssociationClass()
{
- return !AllNavigationProperties().Any()
+ return ModelRoot.IsEFCore5Plus
+ && !AllNavigationProperties().Any()
&& string.IsNullOrEmpty(BaseClass)
&& !IsAssociationClass
&& !IsAbstract
@@ -554,15 +555,15 @@ internal void ConvertToAssociationClass(BidirectionalAssociation bidirectionalAs
}
, new[]
{
- new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, $"{bidirectionalAssociation.TargetPropertyName}_{Name}")
- , new PropertyAssignment(BidirectionalAssociation.SourcePropertyNameDomainPropertyId, $"{bidirectionalAssociation.SourcePropertyName}")
- , new PropertyAssignment(Association.TargetDisplayTextDomainPropertyId, $"Association object for {bidirectionalAssociation.TargetPropertyName}")
+ // new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, $"{bidirectionalAssociation.TargetPropertyName}_{Name}")
+ //, new PropertyAssignment(BidirectionalAssociation.SourcePropertyNameDomainPropertyId, $"{bidirectionalAssociation.SourcePropertyName}")
+ new PropertyAssignment(Association.TargetDisplayTextDomainPropertyId, $"Association object for {bidirectionalAssociation.TargetPropertyName}")
, new PropertyAssignment(BidirectionalAssociation.SourceDisplayTextDomainPropertyId, $"Association object for {bidirectionalAssociation.SourcePropertyName}")
, new PropertyAssignment(Association.TargetSummaryDomainPropertyId, $"Association class for {bidirectionalAssociation.TargetPropertyName}")
, new PropertyAssignment(BidirectionalAssociation.SourceSummaryDomainPropertyId, $"Association class for {bidirectionalAssociation.SourcePropertyName}")
, new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, Multiplicity.One)
, new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, Multiplicity.ZeroMany)
- , new PropertyAssignment(Association.FKPropertyNameDomainPropertyId, $"{bidirectionalAssociation.TargetPropertyName}Id")
+ , new PropertyAssignment(Association.FKPropertyNameDomainPropertyId, $"{bidirectionalAssociation.SourcePropertyName}Id")
});
// ReSharper disable once UnusedVariable
@@ -575,15 +576,15 @@ internal void ConvertToAssociationClass(BidirectionalAssociation bidirectionalAs
}
, new[]
{
- new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, $"{bidirectionalAssociation.SourcePropertyName}_{Name}")
- , new PropertyAssignment(BidirectionalAssociation.SourcePropertyNameDomainPropertyId, $"{bidirectionalAssociation.TargetPropertyName}")
- , new PropertyAssignment(Association.TargetDisplayTextDomainPropertyId, $"Association object for {bidirectionalAssociation.SourcePropertyName}")
+ // new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, $"{bidirectionalAssociation.SourcePropertyName}_{Name}")
+ //, new PropertyAssignment(BidirectionalAssociation.SourcePropertyNameDomainPropertyId, $"{bidirectionalAssociation.TargetPropertyName}")
+ new PropertyAssignment(Association.TargetDisplayTextDomainPropertyId, $"Association object for {bidirectionalAssociation.SourcePropertyName}")
, new PropertyAssignment(BidirectionalAssociation.SourceDisplayTextDomainPropertyId, $"Association object for {bidirectionalAssociation.TargetPropertyName}")
, new PropertyAssignment(Association.TargetSummaryDomainPropertyId, $"Association class for {bidirectionalAssociation.SourcePropertyName}")
, new PropertyAssignment(BidirectionalAssociation.SourceSummaryDomainPropertyId, $"Association class for {bidirectionalAssociation.TargetPropertyName}")
, new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, Multiplicity.One)
, new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, Multiplicity.ZeroMany)
- , new PropertyAssignment(Association.FKPropertyNameDomainPropertyId, $"{bidirectionalAssociation.SourcePropertyName}Id")
+ , new PropertyAssignment(Association.FKPropertyNameDomainPropertyId, $"{bidirectionalAssociation.TargetPropertyName}Id")
});
// set some properties in the association class
diff --git a/src/Dsl/CustomCode/Rules/ClassShapeChangeRules.cs b/src/Dsl/CustomCode/Rules/ClassShapeChangeRules.cs
new file mode 100644
index 000000000..83e24bd83
--- /dev/null
+++ b/src/Dsl/CustomCode/Rules/ClassShapeChangeRules.cs
@@ -0,0 +1,122 @@
+//using System;
+//using System.Collections.Generic;
+//using System.IO;
+//using System.Linq;
+//using System.Windows.Forms;
+
+//using Microsoft.VisualStudio.Modeling;
+//using Microsoft.VisualStudio.Modeling.Diagrams;
+
+//namespace Sawczyn.EFDesigner.EFModel
+//{
+// [RuleOn(typeof(ClassShape), FireTime = TimeToFire.TopLevelCommit)]
+// internal class ClassShapeChangeRules : ChangeRule
+// {
+// ///
+// public override void ElementPropertyChanged(ElementPropertyChangedEventArgs e)
+// {
+// base.ElementPropertyChanged(e);
+
+// ClassShape element = (ClassShape)e.ModelElement;
+
+// if (element.IsDeleted)
+// return;
+
+// ModelClass modelClass = (ModelClass)element.ModelElement;
+// Store store = element.Store;
+// Transaction current = store.TransactionManager.CurrentTransaction;
+
+// if (current.IsSerializing || ModelRoot.BatchUpdating)
+// return;
+
+// if (Equals(e.NewValue, e.OldValue))
+// return;
+
+// List errorMessages = new List();
+
+// switch (e.DomainProperty.Name)
+// {
+// case "AbsoluteBounds":
+// {
+// if (modelClass.CanBecomeAssociationClass())
+// {
+// RectangleD oldBounds = (RectangleD)e.OldValue;
+// RectangleD newBounds = element.AbsoluteBoundingBox;
+// double dw = newBounds.Width - oldBounds.Width;
+// double dh = newBounds.Height - oldBounds.Height;
+// double dx = newBounds.X - oldBounds.X;
+// double dy = newBounds.Y - oldBounds.Y;
+
+// // Moved or resized? If moving, height and width don't change.
+// if (dw != 0.0 && dh != 0.0)
+// break;
+
+// List candidates = GetBidirectionalConnectorsUnderShape(modelClass, store, element);
+
+// if (candidates.Any())
+// {
+// foreach (BidirectionalConnector candidate in candidates)
+// {
+// BidirectionalAssociation association = ((BidirectionalAssociation)candidate.ModelElement);
+
+// if (BooleanQuestionDisplay.Show(store, $"Make {modelClass.Name} an association class for {association.GetDisplayText()}?") == true)
+// {
+// ClassShape.AddAssociationClass(candidate, element);
+// break;
+// }
+// }
+// }
+// }
+// }
+
+// break;
+// }
+
+// errorMessages = errorMessages.Where(m => m != null).ToList();
+
+// if (errorMessages.Any())
+// {
+// current.Rollback();
+// ErrorDisplay.Show(store, string.Join("\n", errorMessages));
+// }
+// }
+
+// private static List GetBidirectionalConnectorsUnderShape(ModelClass modelClass, Store store, ClassShape element)
+// {
+// List linkedConnectionObjectIds = modelClass.Store.ElementDirectory.AllElements
+// .OfType()
+// .Where(x => x.IsAssociationClass)
+// .Select(x => x.DescribedAssociationElementId)
+// .ToList();
+
+// List candidates = store.ElementDirectory.AllElements
+// .OfType()
+// .Where(c => ((BidirectionalAssociation)c.ModelElement).SourceMultiplicity == Multiplicity.ZeroMany
+// && ((BidirectionalAssociation)c.ModelElement).TargetMultiplicity == Multiplicity.ZeroMany
+// && !linkedConnectionObjectIds.Contains(((BidirectionalAssociation)c.ModelElement).Id)
+// && c.Diagram.Id == element.Diagram.Id
+// && c.AbsoluteBoundingBox.IntersectsWith(element.AbsoluteBoundingBox))
+// .ToList();
+
+// return candidates;
+// }
+
+// private static Cursor _moveCursor;
+
+// private static Cursor MoveCursor
+// {
+// get
+// {
+// if (_moveCursor == null)
+// {
+// using (MemoryStream stream = new MemoryStream(Resources.MoveCursor))
+// {
+// _moveCursor = new Cursor(stream);
+// }
+// }
+
+// return _moveCursor;
+// }
+// }
+// }
+//}
diff --git a/src/Dsl/CustomCode/Rules/ModelClassChangeRules.cs b/src/Dsl/CustomCode/Rules/ModelClassChangeRules.cs
index 2bd682338..9501b9f46 100644
--- a/src/Dsl/CustomCode/Rules/ModelClassChangeRules.cs
+++ b/src/Dsl/CustomCode/Rules/ModelClassChangeRules.cs
@@ -415,6 +415,14 @@ public override void ElementPropertyChanged(ElementPropertyChangedEventArgs e)
break;
}
+ case "Summary":
+ {
+ if (string.IsNullOrEmpty(element.TableComment) || element.TableComment == (string)e.OldValue)
+ element.TableComment = element.Summary;
+
+ break;
+ }
+
case "TableName":
{
if (!element.IsDatabaseView)
diff --git a/src/Dsl/CustomCode/Type Descriptors/ModelClassTypeDescriptor.cs b/src/Dsl/CustomCode/Type Descriptors/ModelClassTypeDescriptor.cs
index 01f3cf7ca..96777a238 100644
--- a/src/Dsl/CustomCode/Type Descriptors/ModelClassTypeDescriptor.cs
+++ b/src/Dsl/CustomCode/Type Descriptors/ModelClassTypeDescriptor.cs
@@ -34,6 +34,7 @@ private PropertyDescriptorCollection GetCustomProperties(Attribute[] attributes)
// things unavailable if pre-EFCore5
if (!modelRoot.IsEFCore5Plus)
{
+ propertyDescriptors.Remove("TableComment");
propertyDescriptors.Remove("IsPropertyBag");
propertyDescriptors.Remove("IsQueryType");
propertyDescriptors.Remove("ExcludeFromMigrations");
@@ -45,15 +46,22 @@ private PropertyDescriptorCollection GetCustomProperties(Attribute[] attributes)
}
else
{
+ if (!modelRoot.GenerateTableComments)
+ propertyDescriptors.Remove("TableComment");
+
if (modelClass.IsQueryType)
{
propertyDescriptors.Remove("TableName");
+ propertyDescriptors.Remove("TableComment");
propertyDescriptors.Remove("DatabaseSchema");
propertyDescriptors.Remove("Concurrency");
}
if (modelClass.IsDatabaseView)
+ {
propertyDescriptors.Remove("TableName");
+ propertyDescriptors.Remove("TableComment");
+ }
else
propertyDescriptors.Remove("ViewName");
@@ -75,6 +83,7 @@ private PropertyDescriptorCollection GetCustomProperties(Attribute[] attributes)
propertyDescriptors.Remove("IsQueryType");
propertyDescriptors.Remove("IsDatabaseView");
propertyDescriptors.Remove("ViewName");
+ propertyDescriptors.Remove("ExcludeFromMigrations");
}
//Add the descriptors for the tracking properties
diff --git a/src/Dsl/CustomCode/Type Descriptors/ModelRootTypeDescriptor.cs b/src/Dsl/CustomCode/Type Descriptors/ModelRootTypeDescriptor.cs
index f0b35888d..e7148836e 100644
--- a/src/Dsl/CustomCode/Type Descriptors/ModelRootTypeDescriptor.cs
+++ b/src/Dsl/CustomCode/Type Descriptors/ModelRootTypeDescriptor.cs
@@ -28,9 +28,13 @@ private PropertyDescriptorCollection GetCustomProperties(Attribute[] attributes)
if (modelRoot.GetEntityFrameworkPackageVersionNum() < 2.1)
propertyDescriptors.Remove("LazyLoadingEnabled");
+
+ if (!modelRoot.IsEFCore5Plus)
+ propertyDescriptors.Remove("GenerateTableComments");
}
else
{
+ propertyDescriptors.Remove("GenerateTableComments");
propertyDescriptors.Remove("GenerateDbContextFactory");
propertyDescriptors.Remove("PropertyAccessModeDefault");
propertyDescriptors.Remove("DatabaseCollationDefault");
diff --git a/src/Dsl/CustomCode/Utilities/Import/TextFileProcessor.cs b/src/Dsl/CustomCode/Utilities/Import/TextFileProcessor.cs
index 47a609734..26897c6b8 100644
--- a/src/Dsl/CustomCode/Utilities/Import/TextFileProcessor.cs
+++ b/src/Dsl/CustomCode/Utilities/Import/TextFileProcessor.cs
@@ -567,7 +567,7 @@ private ModelClass ProcessClass([NotNull] ClassDeclarationSyntax classDecl, List
result = new ModelClass(Store
, new PropertyAssignment(ModelClass.NameDomainPropertyId, className)
, new PropertyAssignment(ModelClass.NamespaceDomainPropertyId, namespaceDecl?.Name.ToString() ?? modelRoot.Namespace)
- , new PropertyAssignment(ModelClass.IsAbstractDomainPropertyId, classDecl.DescendantNodes().Any(n => n.Kind() == SyntaxKind.AbstractKeyword)));
+ , new PropertyAssignment(ModelClass.IsAbstractDomainPropertyId, classDecl.DescendantNodes().Any(n => n.IsKind(SyntaxKind.AbstractKeyword))));
newElements.Add(result);
modelRoot.Classes.Add(result);
diff --git a/src/Dsl/CustomCode/Utilities/Nuget/NuGetHelper.cs b/src/Dsl/CustomCode/Utilities/Nuget/NuGetHelper.cs
index e9c0acb1f..de9c7baa5 100644
--- a/src/Dsl/CustomCode/Utilities/Nuget/NuGetHelper.cs
+++ b/src/Dsl/CustomCode/Utilities/Nuget/NuGetHelper.cs
@@ -37,6 +37,7 @@ static NuGetHelper()
public static Dictionary> EFPackageVersions { get; }
public static List NuGetPackageDisplay { get; }
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "Caller requires synchronous method")]
private static void LoadNuGetVersions(EFVersion efVersion, string packageId)
{
// get NuGet packages with that package id
diff --git a/src/Dsl/DslDefinition.dsl b/src/Dsl/DslDefinition.dsl
index c9b873ad1..7fa50ca45 100644
--- a/src/Dsl/DslDefinition.dsl
+++ b/src/Dsl/DslDefinition.dsl
@@ -1,5 +1,5 @@
-
+
@@ -365,6 +365,11 @@
+
+
+
+
+
@@ -608,6 +613,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -827,7 +845,7 @@
-
+
@@ -2344,6 +2362,9 @@
+
+
+
@@ -2463,6 +2484,9 @@
+
+
+
diff --git a/src/Dsl/DslDefinition.dsl.diagram b/src/Dsl/DslDefinition.dsl.diagram
index 55db46fde..113f27f23 100644
--- a/src/Dsl/DslDefinition.dsl.diagram
+++ b/src/Dsl/DslDefinition.dsl.diagram
@@ -4,7 +4,7 @@
-
+
@@ -22,7 +22,7 @@
-
+
@@ -32,39 +32,39 @@
-
+
-
+
-
+
-
+
-
+
-
+
@@ -104,13 +104,13 @@
-
+
-
+
@@ -128,13 +128,13 @@
-
+
-
+
@@ -143,7 +143,7 @@
-
+
@@ -152,7 +152,7 @@
-
+
@@ -167,31 +167,31 @@
-
+
-
+
-
+
-
+
-
+
@@ -209,7 +209,7 @@
-
+
@@ -230,7 +230,7 @@
-
+
@@ -248,7 +248,7 @@
-
+
@@ -257,7 +257,7 @@
-
+
@@ -333,61 +333,61 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -400,13 +400,13 @@
-
+
-
+
@@ -430,28 +430,28 @@
-
+
-
+
-
+
-
+
@@ -464,49 +464,49 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -519,26 +519,26 @@
-
+
-
+
-
+
-
+
@@ -551,54 +551,54 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/src/Dsl/GeneratedCode/DomainClasses.cs b/src/Dsl/GeneratedCode/DomainClasses.cs
index b971dd4fe..e93221b94 100644
--- a/src/Dsl/GeneratedCode/DomainClasses.cs
+++ b/src/Dsl/GeneratedCode/DomainClasses.cs
@@ -4692,6 +4692,95 @@ public override sealed void SetValue(ModelRoot element, global::System.Boolean n
}
}
+ #endregion
+ #region GenerateTableComments domain property code
+
+ ///
+ /// GenerateTableComments domain property Id.
+ ///
+ public static readonly global::System.Guid GenerateTableCommentsDomainPropertyId = new global::System.Guid(0x65d03977, 0x253f, 0x4e9c, 0xa9, 0x46, 0x14, 0xd0, 0xe4, 0x16, 0x44, 0x6d);
+
+ ///
+ /// Storage for GenerateTableComments
+ ///
+ private global::System.Boolean generateTableCommentsPropertyStorage = true;
+
+ ///
+ /// Gets or sets the value of GenerateTableComments domain property.
+ /// If true, will allow generating [Comment] attributes on C# class
+ ///
+ [DslDesign::DisplayNameResource("Sawczyn.EFDesigner.EFModel.ModelRoot/GenerateTableComments.DisplayName", typeof(global::Sawczyn.EFDesigner.EFModel.EFModelDomainModel), "Sawczyn.EFDesigner.EFModel.GeneratedCode.DomainModelResx")]
+ [DslDesign::CategoryResource("Sawczyn.EFDesigner.EFModel.ModelRoot/GenerateTableComments.Category", typeof(global::Sawczyn.EFDesigner.EFModel.EFModelDomainModel), "Sawczyn.EFDesigner.EFModel.GeneratedCode.DomainModelResx")]
+ [DslDesign::DescriptionResource("Sawczyn.EFDesigner.EFModel.ModelRoot/GenerateTableComments.Description", typeof(global::Sawczyn.EFDesigner.EFModel.EFModelDomainModel), "Sawczyn.EFDesigner.EFModel.GeneratedCode.DomainModelResx")]
+ [global::System.ComponentModel.DefaultValue(true)]
+ [DslModeling::DomainObjectId("65d03977-253f-4e9c-a946-14d0e416446d")]
+ public global::System.Boolean GenerateTableComments
+ {
+ [global::System.Diagnostics.DebuggerStepThrough]
+ get
+ {
+ return generateTableCommentsPropertyStorage;
+ }
+ [global::System.Diagnostics.DebuggerStepThrough]
+ set
+ {
+ GenerateTableCommentsPropertyHandler.Instance.SetValue(this, value);
+ }
+ }
+ ///
+ /// Value handler for the ModelRoot.GenerateTableComments domain property.
+ ///
+ internal sealed partial class GenerateTableCommentsPropertyHandler : DslModeling::DomainPropertyValueHandler
+ {
+ private GenerateTableCommentsPropertyHandler() { }
+
+ ///
+ /// Gets the singleton instance of the ModelRoot.GenerateTableComments domain property value handler.
+ ///
+ public static readonly GenerateTableCommentsPropertyHandler Instance = new GenerateTableCommentsPropertyHandler();
+
+ ///
+ /// Gets the Id of the ModelRoot.GenerateTableComments domain property.
+ ///
+ public sealed override global::System.Guid DomainPropertyId
+ {
+ [global::System.Diagnostics.DebuggerStepThrough]
+ get
+ {
+ return GenerateTableCommentsDomainPropertyId;
+ }
+ }
+
+ ///
+ /// Gets a strongly-typed value of the property on specified element.
+ ///
+ /// Element which owns the property.
+ /// Property value.
+ public override sealed global::System.Boolean GetValue(ModelRoot element)
+ {
+ if (element == null) throw new global::System.ArgumentNullException("element");
+ return element.generateTableCommentsPropertyStorage;
+ }
+
+ ///
+ /// Sets property value on an element.
+ ///
+ /// Element which owns the property.
+ /// New property value.
+ public override sealed void SetValue(ModelRoot element, global::System.Boolean newValue)
+ {
+ if (element == null) throw new global::System.ArgumentNullException("element");
+
+ global::System.Boolean oldValue = GetValue(element);
+ if (newValue != oldValue)
+ {
+ ValueChanging(element, oldValue, newValue);
+ element.generateTableCommentsPropertyStorage = newValue;
+ ValueChanged(element, oldValue, newValue);
+ }
+ }
+ }
+
#endregion
#region Comments opposite domain role accessor
@@ -7882,6 +7971,95 @@ public override sealed void SetValue(ModelClass element, global::System.Guid new
}
}
+ #endregion
+ #region TableComment domain property code
+
+ ///
+ /// TableComment domain property Id.
+ ///
+ public static readonly global::System.Guid TableCommentDomainPropertyId = new global::System.Guid(0x221e8cda, 0xf6f7, 0x49e6, 0xa0, 0x3c, 0x9e, 0xe9, 0xce, 0x27, 0x55, 0xff);
+
+ ///
+ /// Storage for TableComment
+ ///
+ private global::System.String tableCommentPropertyStorage = string.Empty;
+
+ ///
+ /// Gets or sets the value of TableComment domain property.
+ /// Table comment that will be applied to the database, if possible
+ ///
+ [System.ComponentModel.Editor(typeof(System.ComponentModel.Design.MultilineStringEditor), typeof(System.Drawing.Design.UITypeEditor))]
+ [DslDesign::DisplayNameResource("Sawczyn.EFDesigner.EFModel.ModelClass/TableComment.DisplayName", typeof(global::Sawczyn.EFDesigner.EFModel.EFModelDomainModel), "Sawczyn.EFDesigner.EFModel.GeneratedCode.DomainModelResx")]
+ [DslDesign::CategoryResource("Sawczyn.EFDesigner.EFModel.ModelClass/TableComment.Category", typeof(global::Sawczyn.EFDesigner.EFModel.EFModelDomainModel), "Sawczyn.EFDesigner.EFModel.GeneratedCode.DomainModelResx")]
+ [DslDesign::DescriptionResource("Sawczyn.EFDesigner.EFModel.ModelClass/TableComment.Description", typeof(global::Sawczyn.EFDesigner.EFModel.EFModelDomainModel), "Sawczyn.EFDesigner.EFModel.GeneratedCode.DomainModelResx")]
+ [DslModeling::DomainObjectId("221e8cda-f6f7-49e6-a03c-9ee9ce2755ff")]
+ public global::System.String TableComment
+ {
+ [global::System.Diagnostics.DebuggerStepThrough]
+ get
+ {
+ return tableCommentPropertyStorage;
+ }
+ [global::System.Diagnostics.DebuggerStepThrough]
+ set
+ {
+ TableCommentPropertyHandler.Instance.SetValue(this, value);
+ }
+ }
+ ///
+ /// Value handler for the ModelClass.TableComment domain property.
+ ///
+ internal sealed partial class TableCommentPropertyHandler : DslModeling::DomainPropertyValueHandler
+ {
+ private TableCommentPropertyHandler() { }
+
+ ///
+ /// Gets the singleton instance of the ModelClass.TableComment domain property value handler.
+ ///
+ public static readonly TableCommentPropertyHandler Instance = new TableCommentPropertyHandler();
+
+ ///
+ /// Gets the Id of the ModelClass.TableComment domain property.
+ ///
+ public sealed override global::System.Guid DomainPropertyId
+ {
+ [global::System.Diagnostics.DebuggerStepThrough]
+ get
+ {
+ return TableCommentDomainPropertyId;
+ }
+ }
+
+ ///
+ /// Gets a strongly-typed value of the property on specified element.
+ ///
+ /// Element which owns the property.
+ /// Property value.
+ public override sealed global::System.String GetValue(ModelClass element)
+ {
+ if (element == null) throw new global::System.ArgumentNullException("element");
+ return element.tableCommentPropertyStorage;
+ }
+
+ ///
+ /// Sets property value on an element.
+ ///
+ /// Element which owns the property.
+ /// New property value.
+ public override sealed void SetValue(ModelClass element, global::System.String newValue)
+ {
+ if (element == null) throw new global::System.ArgumentNullException("element");
+
+ global::System.String oldValue = GetValue(element);
+ if (newValue != oldValue)
+ {
+ ValueChanging(element, oldValue, newValue);
+ element.tableCommentPropertyStorage = newValue;
+ ValueChanged(element, oldValue, newValue);
+ }
+ }
+ }
+
#endregion
#region Targets opposite domain role accessor
@@ -10830,7 +11008,7 @@ public override sealed void SetValue(ModelAttribute element, global::System.Bool
[global::System.ComponentModel.Browsable(false)]
[global::System.ComponentModel.ReadOnly(true)]
[DslModeling::DomainObjectId("8282d835-2c0e-4d59-a638-6d3c6e494260")]
- internal global::System.Guid IsForeignKeyFor
+ public global::System.Guid IsForeignKeyFor
{
[global::System.Diagnostics.DebuggerStepThrough]
get
@@ -10838,7 +11016,7 @@ public override sealed void SetValue(ModelAttribute element, global::System.Bool
return isForeignKeyForPropertyStorage;
}
[global::System.Diagnostics.DebuggerStepThrough]
- set
+ internal set
{
IsForeignKeyForPropertyHandler.Instance.SetValue(this, value);
}
@@ -13794,6 +13972,6 @@ namespace Sawczyn.EFDesigner.EFModel
///
partial class ModelRoot
{
- public const string DSLVersion = "4.0.1.1";
+ public const string DSLVersion = "4.1.2.0";
}
}
diff --git a/src/Dsl/GeneratedCode/DomainModel.cs b/src/Dsl/GeneratedCode/DomainModel.cs
index 851fcc7ca..adebf0f3d 100644
--- a/src/Dsl/GeneratedCode/DomainModel.cs
+++ b/src/Dsl/GeneratedCode/DomainModel.cs
@@ -168,6 +168,7 @@ protected sealed override DomainMemberInfo[] GetGeneratedDomainProperties()
new DomainMemberInfo(typeof(ModelRoot), "ShadowKeyNamePattern", ModelRoot.ShadowKeyNamePatternDomainPropertyId, typeof(ModelRoot.ShadowKeyNamePatternPropertyHandler)),
new DomainMemberInfo(typeof(ModelRoot), "AutoPropertyDefault", ModelRoot.AutoPropertyDefaultDomainPropertyId, typeof(ModelRoot.AutoPropertyDefaultPropertyHandler)),
new DomainMemberInfo(typeof(ModelRoot), "ShowInterfaceIndicators", ModelRoot.ShowInterfaceIndicatorsDomainPropertyId, typeof(ModelRoot.ShowInterfaceIndicatorsPropertyHandler)),
+ new DomainMemberInfo(typeof(ModelRoot), "GenerateTableComments", ModelRoot.GenerateTableCommentsDomainPropertyId, typeof(ModelRoot.GenerateTableCommentsPropertyHandler)),
new DomainMemberInfo(typeof(ModelClass), "IsAbstract", ModelClass.IsAbstractDomainPropertyId, typeof(ModelClass.IsAbstractPropertyHandler)),
new DomainMemberInfo(typeof(ModelClass), "TableName", ModelClass.TableNameDomainPropertyId, typeof(ModelClass.TableNamePropertyHandler)),
new DomainMemberInfo(typeof(ModelClass), "DatabaseSchema", ModelClass.DatabaseSchemaDomainPropertyId, typeof(ModelClass.DatabaseSchemaPropertyHandler)),
@@ -201,6 +202,7 @@ protected sealed override DomainMemberInfo[] GetGeneratedDomainProperties()
new DomainMemberInfo(typeof(ModelClass), "UseTemporalTables", ModelClass.UseTemporalTablesDomainPropertyId, typeof(ModelClass.UseTemporalTablesPropertyHandler)),
new DomainMemberInfo(typeof(ModelClass), "IsAssociationClass", ModelClass.IsAssociationClassDomainPropertyId, typeof(ModelClass.IsAssociationClassPropertyHandler)),
new DomainMemberInfo(typeof(ModelClass), "DescribedAssociationElementId", ModelClass.DescribedAssociationElementIdDomainPropertyId, typeof(ModelClass.DescribedAssociationElementIdPropertyHandler)),
+ new DomainMemberInfo(typeof(ModelClass), "TableComment", ModelClass.TableCommentDomainPropertyId, typeof(ModelClass.TableCommentPropertyHandler)),
new DomainMemberInfo(typeof(ModelAttribute), "Type", ModelAttribute.TypeDomainPropertyId, typeof(ModelAttribute.TypePropertyHandler)),
new DomainMemberInfo(typeof(ModelAttribute), "InitialValue", ModelAttribute.InitialValueDomainPropertyId, typeof(ModelAttribute.InitialValuePropertyHandler)),
new DomainMemberInfo(typeof(ModelAttribute), "IsIdentity", ModelAttribute.IsIdentityDomainPropertyId, typeof(ModelAttribute.IsIdentityPropertyHandler)),
diff --git a/src/Dsl/GeneratedCode/DomainModelResx.resx b/src/Dsl/GeneratedCode/DomainModelResx.resx
index 2a31e5676..5d123fdb7 100644
--- a/src/Dsl/GeneratedCode/DomainModelResx.resx
+++ b/src/Dsl/GeneratedCode/DomainModelResx.resx
@@ -753,6 +753,18 @@
Designer
Category for DomainProperty 'ShowInterfaceIndicators' on DomainClass 'ModelRoot'
+
+ If true, will allow generating [Comment] attributes on C# class
+ Description for DomainProperty 'GenerateTableComments' on DomainClass 'ModelRoot'
+
+
+ Generate Table Comments
+ DisplayName for DomainProperty 'GenerateTableComments' on DomainClass 'ModelRoot'
+
+
+ Database
+ Category for DomainProperty 'GenerateTableComments' on DomainClass 'ModelRoot'
+
Description for DomainClass 'ModelClass'
@@ -1125,6 +1137,18 @@
Described Association Element Id
DisplayName for DomainProperty 'DescribedAssociationElementId' on DomainClass 'ModelClass'
+
+ Table comment that will be applied to the database, if possible
+ Description for DomainProperty 'TableComment' on DomainClass 'ModelClass'
+
+
+ Table Comment
+ DisplayName for DomainProperty 'TableComment' on DomainClass 'ModelClass'
+
+
+ Database
+ Category for DomainProperty 'TableComment' on DomainClass 'ModelClass'
+
An attribute of a class.
Description for DomainClass 'ModelAttribute'
diff --git a/src/Dsl/GeneratedCode/EFModelSchema.xsd b/src/Dsl/GeneratedCode/EFModelSchema.xsd
index 1630caa4f..663111d2c 100644
--- a/src/Dsl/GeneratedCode/EFModelSchema.xsd
+++ b/src/Dsl/GeneratedCode/EFModelSchema.xsd
@@ -387,6 +387,12 @@
If true, will display a UML interface glyph on classes that have custom interfaces defined
+
+
+
+ If true, will allow generating [Comment] attributes on C# class
+
+
@@ -664,6 +670,12 @@
When IsAssociationClass is true, the element id of the association this entity extends
+
+
+
+ Table comment that will be applied to the database, if possible
+
+
diff --git a/src/Dsl/GeneratedCode/LanguageNameSchema.xsd b/src/Dsl/GeneratedCode/LanguageNameSchema.xsd
index 1630caa4f..663111d2c 100644
--- a/src/Dsl/GeneratedCode/LanguageNameSchema.xsd
+++ b/src/Dsl/GeneratedCode/LanguageNameSchema.xsd
@@ -387,6 +387,12 @@
If true, will display a UML interface glyph on classes that have custom interfaces defined
+
+
+
+ If true, will allow generating [Comment] attributes on C# class
+
+
@@ -664,6 +670,12 @@
When IsAssociationClass is true, the element id of the association this entity extends
+
+
+
+ Table comment that will be applied to the database, if possible
+
+
diff --git a/src/Dsl/GeneratedCode/SerializationHelper.cs b/src/Dsl/GeneratedCode/SerializationHelper.cs
index db218641b..13a75c0b4 100644
--- a/src/Dsl/GeneratedCode/SerializationHelper.cs
+++ b/src/Dsl/GeneratedCode/SerializationHelper.cs
@@ -1168,7 +1168,7 @@ public virtual void WriteRootElement(DslModeling::SerializationContext serializa
// Only model has schema, diagram has no schema.
rootElementSettings.SchemaTargetNamespace = "http://schemas.microsoft.com/dsltools/EFModel";
}
- rootElementSettings.Version = new global::System.Version("4.0.1.1");
+ rootElementSettings.Version = new global::System.Version("4.1.2.0");
// Carry out the normal serialization.
rootSerializer.Write(serializationContext, rootElement, writer, rootElementSettings);
@@ -1190,7 +1190,7 @@ protected virtual void CheckVersion(DslModeling::SerializationContext serializat
throw new global::System.ArgumentNullException("reader");
#endregion
- global::System.Version expectedVersion = new global::System.Version("4.0.1.1");
+ global::System.Version expectedVersion = new global::System.Version("4.1.2.0");
string dslVersionStr = reader.GetAttribute("dslVersion");
if (dslVersionStr != null)
{
diff --git a/src/Dsl/GeneratedCode/Serializer.cs b/src/Dsl/GeneratedCode/Serializer.cs
index 967542813..9a8b4bf95 100644
--- a/src/Dsl/GeneratedCode/Serializer.cs
+++ b/src/Dsl/GeneratedCode/Serializer.cs
@@ -1004,6 +1004,23 @@ protected override void ReadPropertiesFromAttributes(DslModeling::SerializationC
}
}
}
+ // GenerateTableComments
+ if (!serializationContext.Result.Failed)
+ {
+ string attribGenerateTableComments = EFModelSerializationHelper.Instance.ReadAttribute(serializationContext, element, reader, "generateTableComments");
+ if (attribGenerateTableComments != null)
+ {
+ global::System.Boolean valueOfGenerateTableComments;
+ if (DslModeling::SerializationUtilities.TryGetValue(serializationContext, attribGenerateTableComments, out valueOfGenerateTableComments))
+ {
+ instanceOfModelRoot.GenerateTableComments = valueOfGenerateTableComments;
+ }
+ else
+ { // Invalid property value, ignored.
+ EFModelSerializationBehaviorSerializationMessages.IgnoredPropertyValue(serializationContext, reader, "generateTableComments", typeof(global::System.Boolean), attribGenerateTableComments);
+ }
+ }
+ }
}
///
@@ -2296,6 +2313,19 @@ protected override void WritePropertiesAsAttributes(DslModeling::SerializationCo
EFModelSerializationHelper.Instance.WriteAttributeString(serializationContext, element, writer, "showInterfaceIndicators", serializedPropValue);
}
}
+ // GenerateTableComments
+ if (!serializationContext.Result.Failed)
+ {
+ global::System.Boolean propValue = instanceOfModelRoot.GenerateTableComments;
+ string serializedPropValue = DslModeling::SerializationUtilities.GetString(serializationContext, propValue);
+ if (!serializationContext.Result.Failed)
+ {
+ if (serializationContext.WriteOptionalPropertiesWithDefaultValue || string.CompareOrdinal(serializedPropValue, "true") != 0)
+ { // No need to write the value out if it's the same as default value.
+ EFModelSerializationHelper.Instance.WriteAttributeString(serializationContext, element, writer, "generateTableComments", serializedPropValue);
+ }
+ }
+ }
}
///
@@ -3119,6 +3149,23 @@ protected override void ReadPropertiesFromAttributes(DslModeling::SerializationC
}
}
}
+ // TableComment
+ if (!serializationContext.Result.Failed)
+ {
+ string attribTableComment = EFModelSerializationHelper.Instance.ReadAttribute(serializationContext, element, reader, "tableComment");
+ if (attribTableComment != null)
+ {
+ global::System.String valueOfTableComment;
+ if (DslModeling::SerializationUtilities.TryGetValue(serializationContext, attribTableComment, out valueOfTableComment))
+ {
+ instanceOfModelClass.TableComment = valueOfTableComment;
+ }
+ else
+ { // Invalid property value, ignored.
+ EFModelSerializationBehaviorSerializationMessages.IgnoredPropertyValue(serializationContext, reader, "tableComment", typeof(global::System.String), attribTableComment);
+ }
+ }
+ }
}
///
@@ -4166,6 +4213,17 @@ protected override void WritePropertiesAsAttributes(DslModeling::SerializationCo
EFModelSerializationHelper.Instance.WriteAttributeString(serializationContext, element, writer, "describedAssociationElementId", serializedPropValue);
}
}
+ // TableComment
+ if (!serializationContext.Result.Failed)
+ {
+ global::System.String propValue = instanceOfModelClass.TableComment;
+ if (!serializationContext.Result.Failed)
+ {
+ if (!string.IsNullOrEmpty(propValue))
+ EFModelSerializationHelper.Instance.WriteAttributeString(serializationContext, element, writer, "tableComment", propValue);
+
+ }
+ }
}
///
@@ -5867,10 +5925,7 @@ protected override void WritePropertiesAsAttributes(DslModeling::SerializationCo
// IsForeignKeyFor
if (!serializationContext.Result.Failed)
{
- // Non-public getter, use DomainPropertyInfo method.
- DslModeling::DomainPropertyInfo propInfo = instanceOfModelAttribute.Partition.DomainDataDirectory.GetDomainProperty (ModelAttribute.IsForeignKeyForDomainPropertyId);
- global::System.Diagnostics.Debug.Assert (propInfo != null, "Cannot get DomainPropertyInfo for ModelAttribute.IsForeignKeyFor!");
- global::System.Guid propValue = ((global::System.Guid)propInfo.GetValue(instanceOfModelAttribute));
+ global::System.Guid propValue = instanceOfModelAttribute.IsForeignKeyFor;
string serializedPropValue = DslModeling::SerializationUtilities.GetString(serializationContext, propValue);
if (!serializationContext.Result.Failed)
{
diff --git a/src/Dsl/GeneratedCode/ToolboxHelper.cs b/src/Dsl/GeneratedCode/ToolboxHelper.cs
index 26841970b..389198baa 100644
--- a/src/Dsl/GeneratedCode/ToolboxHelper.cs
+++ b/src/Dsl/GeneratedCode/ToolboxHelper.cs
@@ -46,35 +46,35 @@ public abstract class EFModelToolboxHelperBase
/// See the MSDN documentation for the ToolboxItemFilterAttribute class for more information on toolbox
/// item filters.
///
- public const string ToolboxFilterString = "EFModel.4.0";
+ public const string ToolboxFilterString = "EFModel.4.1";
///
/// Toolbox item filter string used to identify ModelClass element tool.
///
- public const string ModelClassFilterString = "ModelClass.4.0";
+ public const string ModelClassFilterString = "ModelClass.4.1";
///
/// Toolbox item filter string used to identify UnidirectionalAssociation connector tool.
///
- public const string UnidirectionalAssociationFilterString = "UnidirectionalAssociation.4.0";
+ public const string UnidirectionalAssociationFilterString = "UnidirectionalAssociation.4.1";
///
/// Toolbox item filter string used to identify BidirectionalAssociation connector tool.
///
- public const string BidirectionalAssociationFilterString = "BidirectionalAssociation.4.0";
+ public const string BidirectionalAssociationFilterString = "BidirectionalAssociation.4.1";
///
/// Toolbox item filter string used to identify Generalization connector tool.
///
- public const string GeneralizationFilterString = "Generalization.4.0";
+ public const string GeneralizationFilterString = "Generalization.4.1";
///
/// Toolbox item filter string used to identify Comment element tool.
///
- public const string CommentFilterString = "Comment.4.0";
+ public const string CommentFilterString = "Comment.4.1";
///
/// Toolbox item filter string used to identify CommentLink connector tool.
///
- public const string CommentLinkFilterString = "CommentLink.4.0";
+ public const string CommentLinkFilterString = "CommentLink.4.1";
///
/// Toolbox item filter string used to identify Enumeration element tool.
///
- public const string EnumerationFilterString = "Enumeration.4.0";
+ public const string EnumerationFilterString = "Enumeration.4.1";
private global::System.Collections.Generic.Dictionary toolboxItemCache = new global::System.Collections.Generic.Dictionary();
diff --git a/src/Dsl/Properties/AssemblyInfo.cs b/src/Dsl/Properties/AssemblyInfo.cs
index fd3e258b2..72e292239 100644
--- a/src/Dsl/Properties/AssemblyInfo.cs
+++ b/src/Dsl/Properties/AssemblyInfo.cs
@@ -5,7 +5,7 @@
using System.Runtime.ConstrainedExecution;
[assembly: AssemblyTitle("Entity Framework Visual Designer")]
-[assembly: AssemblyDescription("Entity Framework visual design surface and code-first code generation for EF6, EFCore and beyond")]
+[assembly: AssemblyDescription("Entity Framework visual design surface and code-first code generation for EF6, EFCore and beyond (VS2019 version)")]
#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
@@ -17,8 +17,8 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("3.1.0.0")]
-[assembly: AssemblyFileVersion("3.1.0.0")]
+[assembly: AssemblyVersion("4.1.2.0")]
+[assembly: AssemblyFileVersion("4.1.2.0")]
[assembly: ComVisible(false)]
[assembly: CLSCompliant(true)]
[assembly: ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)]
diff --git a/src/Dsl/Resources.Designer.cs b/src/Dsl/Resources.Designer.cs
index 7cae4ae01..dc6d75a60 100644
--- a/src/Dsl/Resources.Designer.cs
+++ b/src/Dsl/Resources.Designer.cs
@@ -230,6 +230,16 @@ internal class Resources {
}
}
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap Dictionary_16x {
+ get {
+ object obj = ResourceManager.GetObject("Dictionary_16x", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Bitmap.
///
diff --git a/src/Dsl/Resources.resx b/src/Dsl/Resources.resx
index b3c517649..9edf7edfb 100644
--- a/src/Dsl/Resources.resx
+++ b/src/Dsl/Resources.resx
@@ -169,6 +169,9 @@
resources\cardinality-many-many.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+ resources\dictionary_16x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
resources\dictionary_16xvisible.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
diff --git a/src/DslPackage/Commands.vsct b/src/DslPackage/Commands.vsct
index 54d3eaad7..732edc2c9 100644
--- a/src/DslPackage/Commands.vsct
+++ b/src/DslPackage/Commands.vsct
@@ -4,7 +4,7 @@
-
+
@@ -410,7 +410,6 @@
-
@@ -436,7 +435,6 @@
-
@@ -494,7 +492,6 @@
-
diff --git a/src/DslPackage/CustomCode/CommandSet.cs b/src/DslPackage/CustomCode/CommandSet.cs
index b29a85a82..c3714d76a 100644
--- a/src/DslPackage/CustomCode/CommandSet.cs
+++ b/src/DslPackage/CustomCode/CommandSet.cs
@@ -38,7 +38,6 @@ internal partial class EFModelCommandSet
private const int cmdidGenerateCode = 0x0015;
private const int cmdidAddCodeProperties = 0x0016;
private const int cmdidSaveAsImage = 0x0017;
- private const int cmdidLoadNuGet = 0x0018;
private const int cmdidAddCodeValues = 0x0019;
private const int cmdidExpandSelected = 0x001A;
private const int cmdidCollapseSelected = 0x001B;
@@ -197,17 +196,6 @@ protected override IList GetMenuCommands()
#endregion
- #region loadNuGetCommand
-
-#pragma warning disable 612
- DynamicStatusMenuCommand loadNuGetCommand =
- new DynamicStatusMenuCommand(OnStatusLoadNuGet, OnMenuLoadNuGet, new CommandID(guidEFDiagramMenuCmdSet, cmdidLoadNuGet));
-#pragma warning restore 612
-
- commands.Add(loadNuGetCommand);
-
- #endregion
-
#region selectClassesCommand
DynamicStatusMenuCommand selectClassesCommand =
@@ -415,6 +403,13 @@ protected override void ProcessOnMenuDeleteCommand()
}
}
+ if (CurrentSelection.OfType().Any(a => a.ModelClass.IsAssociationClass && a.IsIdentity))
+ {
+ MessageDisplay.Show("Identity attributes of association classes can't be deleted");
+
+ return;
+ }
+
base.ProcessOnMenuDeleteCommand();
}
@@ -1080,31 +1075,6 @@ private void OnMenuImageToClipboard(object sender, EventArgs e)
#endregion
- #region Load NuGet
-
- [Obsolete]
- private void OnStatusLoadNuGet(object sender, EventArgs e)
- {
- if (sender is MenuCommand command)
- {
- //Store store = CurrentDocData.Store;
- //ModelRoot modelRoot = store.ModelRoot();
- command.Visible = false; // modelRoot != null && CurrentDocData is EFModelDocData && IsDiagramSelected();
- command.Enabled = false; // IsDiagramSelected() && ModelRoot.CanLoadNugetPackages;
- }
- }
-
- [Obsolete]
- private void OnMenuLoadNuGet(object sender, EventArgs e)
- {
- //Store store = CurrentDocData.Store;
- //ModelRoot modelRoot = store.ModelRoot();
-
- //((EFModelDocData)CurrentDocData).EnsureCorrectNuGetPackages(modelRoot);
- }
-
- #endregion Load NuGet
-
#region Merge Unidirectional Associations
private void OnStatusMergeAssociations(object sender, EventArgs e)
diff --git a/src/DslPackage/CustomCode/Partials/EFModelDocData.cs b/src/DslPackage/CustomCode/Partials/EFModelDocData.cs
index 66f90788f..ec2a7d76a 100644
--- a/src/DslPackage/CustomCode/Partials/EFModelDocData.cs
+++ b/src/DslPackage/CustomCode/Partials/EFModelDocData.cs
@@ -7,11 +7,8 @@
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
-
using EnvDTE;
-
using EnvDTE80;
-
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Modeling;
@@ -24,6 +21,7 @@
using Sawczyn.EFDesigner.EFModel.Extensions;
using VSLangProj;
+// ReSharper disable MemberCanBePrivate.Global
namespace Sawczyn.EFDesigner.EFModel
{
@@ -32,22 +30,18 @@ internal partial class EFModelDocData
{
private static DTE _dte;
private static DTE2 _dte2;
-
private IComponentModel _componentModel;
-
//private IVsOutputWindowPane _outputWindow;
internal static DTE Dte => _dte ?? (_dte = Package.GetGlobalService(typeof(DTE)) as DTE);
internal static DTE2 Dte2 => _dte2 ?? (_dte2 = Package.GetGlobalService(typeof(SDTE)) as DTE2);
-
internal IComponentModel ComponentModel => _componentModel ?? (_componentModel = (IComponentModel)GetService(typeof(SComponentModel)));
-
//internal IVsOutputWindowPane OutputWindow => _outputWindow ?? (_outputWindow = (IVsOutputWindowPane)GetService(typeof(SVsGeneralOutputWindowPane)));
internal static Project ActiveProject =>
- Dte.ActiveSolutionProjects is Array activeSolutionProjects && activeSolutionProjects.Length > 0
- ? activeSolutionProjects.GetValue(0) as Project
- : null;
+ Dte.ActiveSolutionProjects is Array activeSolutionProjects && activeSolutionProjects.Length > 0
+ ? activeSolutionProjects.GetValue(0) as Project
+ : null;
internal static void GenerateCode()
{
@@ -125,7 +119,6 @@ internal static bool OpenFileFor(ModelClass modelClass)
catch (Exception e)
{
Debug.WriteLine("Error opening file. " + e.Message);
-
return false;
}
}
@@ -159,7 +152,6 @@ internal static bool OpenFileFor(ModelEnum modelEnum)
catch (Exception e)
{
Debug.WriteLine("Error opening file. " + e.Message);
-
return false;
}
}
@@ -378,14 +370,18 @@ private void ValidateModelElement(ModelElement modelElement)
ValidationCategories allCategories = ValidationCategories.Menu | ValidationCategories.Open | ValidationCategories.Save | ValidationCategories.Custom | ValidationCategories.Load;
ValidationController.Validate(modelElement, allCategories);
-
+
displaysWarningElement.RedrawItem();
}
}
internal static DialogResult ShowQuestionBox(IServiceProvider serviceProvider, string question)
{
- return PackageUtility.ShowMessageBox(serviceProvider, question, OLEMSGBUTTON.OLEMSGBUTTON_YESNO, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_SECOND, OLEMSGICON.OLEMSGICON_QUERY);
+ return PackageUtility.ShowMessageBox(serviceProvider,
+ question,
+ OLEMSGBUTTON.OLEMSGBUTTON_YESNO,
+ OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_SECOND,
+ OLEMSGICON.OLEMSGICON_QUERY);
}
internal static bool ShowBooleanQuestionBox(IServiceProvider serviceProvider, string question)
@@ -434,7 +430,6 @@ protected override bool CanSave(bool allowUserInterface)
{
if (allowUserInterface)
ValidationController?.ClearMessages();
-
return base.CanSave(allowUserInterface);
}
@@ -455,8 +450,7 @@ protected override void OnDocumentSaved(EventArgs e)
public void Merge(UnidirectionalAssociation[] selected)
{
- if (!(RootElement is ModelRoot modelRoot))
- return;
+ if (!(RootElement is ModelRoot modelRoot)) return;
using (Transaction tx = modelRoot.Store.TransactionManager.BeginTransaction("Merge associations"))
{
@@ -464,89 +458,105 @@ public void Merge(UnidirectionalAssociation[] selected)
selected[1].Delete();
// ReSharper disable once UnusedVariable
- BidirectionalAssociation element = new BidirectionalAssociation(Store
- , new[]
- {
- new RoleAssignment(BidirectionalAssociation.BidirectionalSourceDomainRoleId, selected[0].Source)
- , new RoleAssignment(BidirectionalAssociation.BidirectionalTargetDomainRoleId, selected[1].Source)
- }
- , new[]
- {
- new PropertyAssignment(BidirectionalAssociation.SourcePropertyNameDomainPropertyId, selected[1].TargetPropertyName)
- , new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, selected[0].TargetPropertyName)
- , new PropertyAssignment(BidirectionalAssociation.SourceCustomAttributesDomainPropertyId
- , selected[1].TargetCustomAttributes)
- , new PropertyAssignment(Association.TargetCustomAttributesDomainPropertyId, selected[0].TargetCustomAttributes)
- , new PropertyAssignment(BidirectionalAssociation.SourceDisplayTextDomainPropertyId, selected[1].TargetDisplayText)
- , new PropertyAssignment(Association.TargetDisplayTextDomainPropertyId, selected[0].TargetDisplayText)
- , new PropertyAssignment(BidirectionalAssociation.SourceSummaryDomainPropertyId, selected[1].TargetSummary)
- , new PropertyAssignment(BidirectionalAssociation.SourceDescriptionDomainPropertyId, selected[1].TargetDescription)
- , new PropertyAssignment(Association.TargetSummaryDomainPropertyId, selected[0].TargetSummary)
- , new PropertyAssignment(Association.TargetDescriptionDomainPropertyId, selected[0].TargetDescription)
- , new PropertyAssignment(Association.SourceDeleteActionDomainPropertyId, selected[1].TargetDeleteAction)
- , new PropertyAssignment(Association.TargetDeleteActionDomainPropertyId, selected[0].TargetDeleteAction)
- , new PropertyAssignment(Association.SourceRoleDomainPropertyId, selected[1].TargetRole)
- , new PropertyAssignment(Association.TargetRoleDomainPropertyId, selected[0].TargetRole)
- , new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, selected[1].TargetMultiplicity)
- , new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, selected[0].TargetMultiplicity)
- });
-
+ BidirectionalAssociation element = new BidirectionalAssociation(Store,
+ new[]
+ {
+ new RoleAssignment(BidirectionalAssociation.BidirectionalSourceDomainRoleId, selected[0].Source),
+ new RoleAssignment(BidirectionalAssociation.BidirectionalTargetDomainRoleId, selected[1].Source)
+ },
+ new[]
+ {
+ new PropertyAssignment(BidirectionalAssociation.SourcePropertyNameDomainPropertyId, selected[1].TargetPropertyName),
+ new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, selected[0].TargetPropertyName),
+
+ new PropertyAssignment(BidirectionalAssociation.SourceCustomAttributesDomainPropertyId, selected[1].TargetCustomAttributes),
+ new PropertyAssignment(Association.TargetCustomAttributesDomainPropertyId, selected[0].TargetCustomAttributes),
+
+ new PropertyAssignment(BidirectionalAssociation.SourceDisplayTextDomainPropertyId, selected[1].TargetDisplayText),
+ new PropertyAssignment(Association.TargetDisplayTextDomainPropertyId, selected[0].TargetDisplayText),
+
+ new PropertyAssignment(BidirectionalAssociation.SourceSummaryDomainPropertyId, selected[1].TargetSummary),
+ new PropertyAssignment(BidirectionalAssociation.SourceDescriptionDomainPropertyId, selected[1].TargetDescription),
+
+ new PropertyAssignment(Association.TargetSummaryDomainPropertyId, selected[0].TargetSummary),
+ new PropertyAssignment(Association.TargetDescriptionDomainPropertyId, selected[0].TargetDescription),
+
+ new PropertyAssignment(Association.SourceDeleteActionDomainPropertyId, selected[1].TargetDeleteAction),
+ new PropertyAssignment(Association.TargetDeleteActionDomainPropertyId, selected[0].TargetDeleteAction),
+
+ new PropertyAssignment(Association.SourceRoleDomainPropertyId, selected[1].TargetRole),
+ new PropertyAssignment(Association.TargetRoleDomainPropertyId, selected[0].TargetRole),
+
+ new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, selected[1].TargetMultiplicity),
+ new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, selected[0].TargetMultiplicity),
+ });
tx.Commit();
}
}
public void Split(BidirectionalAssociation selected)
{
- if (!(RootElement is ModelRoot modelRoot))
- return;
+ if (!(RootElement is ModelRoot modelRoot)) return;
using (Transaction tx = modelRoot.Store.TransactionManager.BeginTransaction("Split associations"))
{
selected.Delete();
// ReSharper disable once UnusedVariable
- UnidirectionalAssociation element1 = new UnidirectionalAssociation(Store
- , new[]
- {
- new RoleAssignment(Association.SourceDomainRoleId, selected.Source)
- , new RoleAssignment(Association.TargetDomainRoleId, selected.Target)
- }
- , new[]
- {
- new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, selected.TargetPropertyName)
- , new PropertyAssignment(Association.TargetCustomAttributesDomainPropertyId, selected.TargetCustomAttributes)
- , new PropertyAssignment(Association.TargetDisplayTextDomainPropertyId, selected.TargetDisplayText)
- , new PropertyAssignment(Association.TargetSummaryDomainPropertyId, selected.TargetSummary)
- , new PropertyAssignment(Association.TargetDescriptionDomainPropertyId, selected.TargetDescription)
- , new PropertyAssignment(Association.SourceDeleteActionDomainPropertyId, selected.SourceDeleteAction)
- , new PropertyAssignment(Association.TargetDeleteActionDomainPropertyId, selected.TargetDeleteAction)
- , new PropertyAssignment(Association.SourceRoleDomainPropertyId, selected.SourceRole)
- , new PropertyAssignment(Association.TargetRoleDomainPropertyId, selected.TargetRole)
- , new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, selected.SourceMultiplicity)
- , new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, selected.TargetMultiplicity)
- });
+ UnidirectionalAssociation element1 = new UnidirectionalAssociation(Store,
+ new[]
+ {
+ new RoleAssignment(Association.SourceDomainRoleId, selected.Source),
+ new RoleAssignment(Association.TargetDomainRoleId, selected.Target)
+ },
+ new[]
+ {
+ new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, selected.TargetPropertyName),
+
+ new PropertyAssignment(Association.TargetCustomAttributesDomainPropertyId, selected.TargetCustomAttributes),
+
+ new PropertyAssignment(Association.TargetDisplayTextDomainPropertyId, selected.TargetDisplayText),
+
+ new PropertyAssignment(Association.TargetSummaryDomainPropertyId, selected.TargetSummary),
+ new PropertyAssignment(Association.TargetDescriptionDomainPropertyId, selected.TargetDescription),
+
+ new PropertyAssignment(Association.SourceDeleteActionDomainPropertyId, selected.SourceDeleteAction),
+ new PropertyAssignment(Association.TargetDeleteActionDomainPropertyId, selected.TargetDeleteAction),
+
+ new PropertyAssignment(Association.SourceRoleDomainPropertyId, selected.SourceRole),
+ new PropertyAssignment(Association.TargetRoleDomainPropertyId, selected.TargetRole),
+
+ new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, selected.SourceMultiplicity),
+ new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, selected.TargetMultiplicity),
+ });
// ReSharper disable once UnusedVariable
- UnidirectionalAssociation element2 = new UnidirectionalAssociation(Store
- , new[]
- {
- new RoleAssignment(Association.SourceDomainRoleId, selected.Target)
- , new RoleAssignment(Association.TargetDomainRoleId, selected.Source)
- }
- , new[]
- {
- new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, selected.SourcePropertyName)
- , new PropertyAssignment(Association.TargetCustomAttributesDomainPropertyId, selected.SourceCustomAttributes)
- , new PropertyAssignment(Association.TargetDisplayTextDomainPropertyId, selected.SourceDisplayText)
- , new PropertyAssignment(Association.TargetSummaryDomainPropertyId, selected.SourceSummary)
- , new PropertyAssignment(Association.TargetDescriptionDomainPropertyId, selected.SourceDescription)
- , new PropertyAssignment(Association.SourceDeleteActionDomainPropertyId, selected.TargetDeleteAction)
- , new PropertyAssignment(Association.TargetDeleteActionDomainPropertyId, selected.SourceDeleteAction)
- , new PropertyAssignment(Association.SourceRoleDomainPropertyId, selected.TargetRole)
- , new PropertyAssignment(Association.TargetRoleDomainPropertyId, selected.SourceRole)
- , new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, selected.TargetMultiplicity)
- , new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, selected.SourceMultiplicity)
- });
+ UnidirectionalAssociation element2 = new UnidirectionalAssociation(Store,
+ new[]
+ {
+ new RoleAssignment(Association.SourceDomainRoleId, selected.Target),
+ new RoleAssignment(Association.TargetDomainRoleId, selected.Source)
+ },
+ new[]
+ {
+ new PropertyAssignment(Association.TargetPropertyNameDomainPropertyId, selected.SourcePropertyName),
+
+ new PropertyAssignment(Association.TargetCustomAttributesDomainPropertyId, selected.SourceCustomAttributes),
+
+ new PropertyAssignment(Association.TargetDisplayTextDomainPropertyId, selected.SourceDisplayText),
+
+ new PropertyAssignment(Association.TargetSummaryDomainPropertyId, selected.SourceSummary),
+ new PropertyAssignment(Association.TargetDescriptionDomainPropertyId, selected.SourceDescription),
+
+ new PropertyAssignment(Association.SourceDeleteActionDomainPropertyId, selected.TargetDeleteAction),
+ new PropertyAssignment(Association.TargetDeleteActionDomainPropertyId, selected.SourceDeleteAction),
+
+ new PropertyAssignment(Association.SourceRoleDomainPropertyId, selected.TargetRole),
+ new PropertyAssignment(Association.TargetRoleDomainPropertyId, selected.SourceRole),
+
+ new PropertyAssignment(Association.SourceMultiplicityDomainPropertyId, selected.TargetMultiplicity),
+ new PropertyAssignment(Association.TargetMultiplicityDomainPropertyId, selected.SourceMultiplicity),
+ });
tx.Commit();
}
@@ -555,7 +565,6 @@ public void Split(BidirectionalAssociation selected)
protected override void CleanupOldDiagramFiles()
{
string diagramsFileName = FileName + this.DiagramExtension;
-
if (diagramsFileName.EndsWith("x"))
{
string oldDiagramFileName = diagramsFileName.TrimEnd('x');
@@ -565,5 +574,4 @@ protected override void CleanupOldDiagramFiles()
}
}
}
-
-}
\ No newline at end of file
+}
diff --git a/src/DslPackage/DslPackage.csproj b/src/DslPackage/DslPackage.csproj
index bf7d04fc0..0b6e1414c 100644
--- a/src/DslPackage/DslPackage.csproj
+++ b/src/DslPackage/DslPackage.csproj
@@ -241,6 +241,7 @@
true
+
@@ -273,6 +274,18 @@
true
+
+
+
+
+
+
+
+
+
+
+
+
Always
@@ -401,6 +414,7 @@
true
+
diff --git a/src/DslPackage/GeneratedCode/Constants.cs b/src/DslPackage/GeneratedCode/Constants.cs
index 00d14bad0..a4bd6219b 100644
--- a/src/DslPackage/GeneratedCode/Constants.cs
+++ b/src/DslPackage/GeneratedCode/Constants.cs
@@ -18,7 +18,7 @@ internal static partial class Constants
[global::System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
public const string CompanyName = @"Michael Sawczyn";
[global::System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
- public const string ProductVersion = "4.0.1.1";
+ public const string ProductVersion = "4.1.2.0";
// Menu definitions
public static readonly global::System.ComponentModel.Design.CommandID EFModelDiagramMenu = new global::System.ComponentModel.Design.CommandID(new global::System.Guid(EFModelCommandSetId), 0x10000);
@@ -40,7 +40,8 @@ internal static partial class Constants
// Model explorer tool window identifier
public const string EFModelModelExplorerToolWindowId = "860f0cbe-0c84-4abe-8062-fa681f8038db";
}
-}//
+}
+//
// Constants not generated from values in DesignerDefinition.dsl are defined below
//
namespace Sawczyn.EFDesigner.EFModel
diff --git a/src/DslPackage/GeneratedCode/Constants.tt b/src/DslPackage/GeneratedCode/Constants.tt
index 969abc906..6ade8b1bd 100644
--- a/src/DslPackage/GeneratedCode/Constants.tt
+++ b/src/DslPackage/GeneratedCode/Constants.tt
@@ -1,5 +1,6 @@
<#@ Dsl processor="DslDirectiveProcessor" requires="fileName='..\..\Dsl\DslDefinition.dsl'" #><#@
-include file="..\Templates\Constants.tt" #>//
+include file="..\Templates\Constants.tt" #>
+//
// Constants not generated from values in DesignerDefinition.dsl are defined below
//
namespace <#= CodeGenerationUtilities.GetPackageNamespace(this.Dsl) #>
diff --git a/src/DslPackage/GeneratedCode/Package.cs b/src/DslPackage/GeneratedCode/Package.cs
index ee4c3a699..8f8779a22 100644
--- a/src/DslPackage/GeneratedCode/Package.cs
+++ b/src/DslPackage/GeneratedCode/Package.cs
@@ -182,7 +182,7 @@ namespace Sawczyn.EFDesigner.EFModel
///
/// Double-derived class to allow easier code customization.
///
- [VSShell::ProvideMenuResource("1000.ctmenu", version: 43)]
+ [VSShell::ProvideMenuResource("1000.ctmenu", version: 44)]
[VSShell::ProvideToolboxItems(1)]
[global::Microsoft.VisualStudio.TextTemplating.VSHost.ProvideDirectiveProcessor(typeof(global::Sawczyn.EFDesigner.EFModel.EFModelDirectiveProcessor), global::Sawczyn.EFDesigner.EFModel.EFModelDirectiveProcessor.EFModelDirectiveProcessorName, "A directive processor that provides access to EFModel files")]
[global::System.Runtime.InteropServices.Guid(Constants.EFModelPackageId)]
diff --git a/src/DslPackage/GeneratedCode/Package.tt b/src/DslPackage/GeneratedCode/Package.tt
index c6c29bcb7..8169e7d20 100644
--- a/src/DslPackage/GeneratedCode/Package.tt
+++ b/src/DslPackage/GeneratedCode/Package.tt
@@ -22,7 +22,7 @@ namespace <#= CodeGenerationUtilities.GetPackageNamespace(this.Dsl) #>
///
/// Double-derived class to allow easier code customization.
///
- [VSShell::ProvideMenuResource("1000.ctmenu", version: 43)]
+ [VSShell::ProvideMenuResource("1000.ctmenu", version: 44)]
[VSShell::ProvideToolboxItems(1)]
[global::Microsoft.VisualStudio.TextTemplating.VSHost.ProvideDirectiveProcessor(typeof(global::<#= this.Dsl.Namespace #>.<#= directiveName #>DirectiveProcessor), global::<#= this.Dsl.Namespace #>.<#= directiveName #>DirectiveProcessor.<#= directiveName #>DirectiveProcessorName, "A directive processor that provides access to <#= directiveName #> files")]
[global::System.Runtime.InteropServices.Guid(Constants.<#= dslName #>PackageId)]
diff --git a/src/DslPackage/Parsers/EF6Parser.exe b/src/DslPackage/Parsers/EF6Parser.exe
index 87c4b1bc0..d3b17f6f0 100644
Binary files a/src/DslPackage/Parsers/EF6Parser.exe and b/src/DslPackage/Parsers/EF6Parser.exe differ
diff --git a/src/DslPackage/Parsers/EFCore2Parser.exe b/src/DslPackage/Parsers/EFCore2Parser.exe
index f4a5cea8c..7fe532a82 100644
Binary files a/src/DslPackage/Parsers/EFCore2Parser.exe and b/src/DslPackage/Parsers/EFCore2Parser.exe differ
diff --git a/src/DslPackage/Parsers/EFCore3Parser.exe b/src/DslPackage/Parsers/EFCore3Parser.exe
index 97a723975..e379e3367 100644
Binary files a/src/DslPackage/Parsers/EFCore3Parser.exe and b/src/DslPackage/Parsers/EFCore3Parser.exe differ
diff --git a/src/DslPackage/Parsers/EFCore5Parser.exe b/src/DslPackage/Parsers/EFCore5Parser.exe
index dcc21151a..297fd0c2c 100644
Binary files a/src/DslPackage/Parsers/EFCore5Parser.exe and b/src/DslPackage/Parsers/EFCore5Parser.exe differ
diff --git a/src/DslPackage/PreviewImage.png b/src/DslPackage/PreviewImage.png
new file mode 100644
index 000000000..abd79712b
Binary files /dev/null and b/src/DslPackage/PreviewImage.png differ
diff --git a/src/DslPackage/ProjectItemTemplates/EFModel.xsd b/src/DslPackage/ProjectItemTemplates/EFModel.xsd
index 1630caa4f..663111d2c 100644
--- a/src/DslPackage/ProjectItemTemplates/EFModel.xsd
+++ b/src/DslPackage/ProjectItemTemplates/EFModel.xsd
@@ -387,6 +387,12 @@
If true, will display a UML interface glyph on classes that have custom interfaces defined
+
+
+
+ If true, will allow generating [Comment] attributes on C# class
+
+
@@ -664,6 +670,12 @@
When IsAssociationClass is true, the element id of the association this entity extends
+
+
+
+ Table comment that will be applied to the database, if possible
+
+
diff --git a/src/DslPackage/Properties/AssemblyInfo.cs b/src/DslPackage/Properties/AssemblyInfo.cs
index 05262c3d2..6bdc9a73a 100644
--- a/src/DslPackage/Properties/AssemblyInfo.cs
+++ b/src/DslPackage/Properties/AssemblyInfo.cs
@@ -16,8 +16,8 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("3.1.0.0")]
-[assembly: AssemblyFileVersion("3.1.0.0")]
+[assembly: AssemblyVersion("4.1.2.0")]
+[assembly: AssemblyFileVersion("4.1.2.0")]
[assembly: ComVisible(false)]
[assembly: CLSCompliant(false)]
[assembly: ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)]
diff --git a/src/DslPackage/TextTemplates/EF6Designer.ttinclude b/src/DslPackage/TextTemplates/EF6Designer.ttinclude
index 9a50423f1..7a297cbdc 100644
--- a/src/DslPackage/TextTemplates/EF6Designer.ttinclude
+++ b/src/DslPackage/TextTemplates/EF6Designer.ttinclude
@@ -23,7 +23,7 @@
#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
-// EFDesigner v3.0.8
+// EFDesigner v4.1.2.0
// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
diff --git a/src/DslPackage/TextTemplates/EF6ModelGenerator.ttinclude b/src/DslPackage/TextTemplates/EF6ModelGenerator.ttinclude
index 9574eef2d..9ecabb9d9 100644
--- a/src/DslPackage/TextTemplates/EF6ModelGenerator.ttinclude
+++ b/src/DslPackage/TextTemplates/EF6ModelGenerator.ttinclude
@@ -23,7 +23,7 @@
#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
- // EFDesigner v3.1.0.0
+ // EFDesigner v4.1.2.0
// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
diff --git a/src/DslPackage/TextTemplates/EFCore2ModelGenerator.ttinclude b/src/DslPackage/TextTemplates/EFCore2ModelGenerator.ttinclude
index 5275b055d..54311b578 100644
--- a/src/DslPackage/TextTemplates/EFCore2ModelGenerator.ttinclude
+++ b/src/DslPackage/TextTemplates/EFCore2ModelGenerator.ttinclude
@@ -23,7 +23,7 @@
#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
- // EFDesigner v3.1.0.0
+ // EFDesigner v4.1.2.0
// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
diff --git a/src/DslPackage/TextTemplates/EFCore3ModelGenerator.ttinclude b/src/DslPackage/TextTemplates/EFCore3ModelGenerator.ttinclude
index 8e7ff1540..0c0f2f884 100644
--- a/src/DslPackage/TextTemplates/EFCore3ModelGenerator.ttinclude
+++ b/src/DslPackage/TextTemplates/EFCore3ModelGenerator.ttinclude
@@ -23,7 +23,7 @@
#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
- // EFDesigner v3.1.0.0
+ // EFDesigner v4.1.2.0
// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
@@ -31,7 +31,7 @@
{
public EFCore3ModelGenerator(GeneratedTextTransformation host) : base(host) { }
- protected override void WriteTargetDeleteBehavior(UnidirectionalAssociation association, List segments)
+ protected override void WriteTargetDeleteBehavior(Association association, List segments)
{
if (!association.Source.IsDependentType
&& !association.Target.IsDependentType
diff --git a/src/DslPackage/TextTemplates/EFCore5ModelGenerator.ttinclude b/src/DslPackage/TextTemplates/EFCore5ModelGenerator.ttinclude
index 9f86066f9..f08c000a3 100644
--- a/src/DslPackage/TextTemplates/EFCore5ModelGenerator.ttinclude
+++ b/src/DslPackage/TextTemplates/EFCore5ModelGenerator.ttinclude
@@ -23,7 +23,7 @@
#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
- // EFDesigner v3.1.0.0
+ // EFDesigner v4.1.2.0
// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
@@ -31,17 +31,114 @@
{
public EFCore5ModelGenerator(GeneratedTextTransformation host) : base(host) { }
+ protected override void ConfigureModelClasses(List segments, ModelClass[] classesWithTables, List foreignKeyColumns, List visited)
+ {
+ foreach (ModelClass modelClass in modelRoot.Classes.Where(x => !x.IsAssociationClass).OrderBy(x => x.Name))
+ ConfigureModelClass(segments, classesWithTables, foreignKeyColumns, visited, modelClass);
+ }
+
+ protected override void ConfigureModelClass(List segments, ModelClass[] classesWithTables, List foreignKeyColumns, List visited, ModelClass modelClass)
+ {
+ segments.Clear();
+ foreignKeyColumns.Clear();
+ NL();
+
+ if (modelClass.IsDependentType)
+ {
+ segments.Add($"modelBuilder.Owned<{modelClass.FullName}>()");
+ Output(segments);
+
+ return;
+ }
+
+ segments.Add($"modelBuilder.Entity<{modelClass.FullName}>()");
+
+ ConfigureTransientProperties(segments, modelClass);
+
+ //if (modelRoot.InheritanceStrategy == CodeStrategy.TablePerConcreteType && modelClass.Superclass != null)
+ // segments.Add("Map(x => x.MapInheritedProperties())");
+
+ if (classesWithTables.Contains(modelClass))
+ {
+ if (modelClass.IsQueryType)
+ {
+ Output($"// There is no storage defined for {modelClass.Name} because its IsQueryType value is");
+ Output($"// set to 'true'. Please provide the {modelRoot.FullName}.Get{modelClass.Name}SqlQuery() method in the partial class.");
+ Output("// ");
+ Output($"// private string Get{modelClass.Name}SqlQuery()");
+ Output("// {");
+ Output($"// return the defining SQL query that pulls all the properties for {modelClass.FullName}");
+ Output("// }");
+
+ segments.Add($"ToSqlQuery(Get{modelClass.Name}SqlQuery())");
+ }
+ else
+ ConfigureTable(segments, modelClass);
+ }
+
+ if (segments.Count > 1 || modelClass.IsDependentType)
+ Output(segments);
+
+ // attribute level
+ ConfigureModelAttributes(segments, modelClass);
+
+ bool hasDefinedConcurrencyToken = modelClass.AllAttributes.Any(x => x.IsConcurrencyToken);
+
+ if (!hasDefinedConcurrencyToken && modelClass.EffectiveConcurrency == ConcurrencyOverride.Optimistic)
+ Output($@"modelBuilder.Entity<{modelClass.FullName}>().Property(""Timestamp"").IsConcurrencyToken();");
+
+ // Navigation endpoints are distingished as Source and Target. They are also distinguished as Principal
+ // and Dependent. So how do these map to each other? Short answer: they don't - they're orthogonal concepts.
+ // Source and Target are accidents of where the user started drawing the association, and help define where the
+ // properties are in unidirectional associations. Principal and Dependent define where the foreign keys go in
+ // the persistence mechanism.
+
+ // What matters to code generation is the Principal and Dependent classifications, so we focus on those.
+ // In the case of 1-1 or 0/1-0/1, it's situational, so the user has to tell us.
+ // In all other cases, we can tell by the cardinalities of the associations.
+
+ // navigation properties
+ List declaredShadowProperties = new List();
+
+ if (!modelClass.IsDependentType)
+ {
+ ConfigureUnidirectionalAssociations(modelClass, visited, foreignKeyColumns, declaredShadowProperties);
+ ConfigureBidirectionalAssociations(modelClass, visited, foreignKeyColumns, declaredShadowProperties);
+ }
+ }
+
protected override void ConfigureTable(List segments, ModelClass modelClass)
{
- string tableName = string.IsNullOrEmpty(modelClass.TableName) ? modelClass.Name : modelClass.TableName;
- string viewName = string.IsNullOrEmpty(modelClass.ViewName) ? modelClass.Name : modelClass.ViewName;
- string schema = string.IsNullOrEmpty(modelClass.DatabaseSchema) || modelClass.DatabaseSchema == modelClass.ModelRoot.DatabaseSchema ? string.Empty : $", \"{modelClass.DatabaseSchema}\"";
- string buildAction = modelClass.ExcludeFromMigrations ? ", t => t.ExcludeFromMigrations()" : string.Empty;
+ string tableName = string.IsNullOrEmpty(modelClass.TableName)
+ ? modelClass.Name
+ : modelClass.TableName;
+
+ string viewName = string.IsNullOrEmpty(modelClass.ViewName)
+ ? modelClass.Name
+ : modelClass.ViewName;
+
+ string schema = string.IsNullOrEmpty(modelClass.DatabaseSchema) || modelClass.DatabaseSchema == modelClass.ModelRoot.DatabaseSchema
+ ? string.Empty
+ : $", \"{modelClass.DatabaseSchema}\"";
+
+ List modifiers = new List();
- if (modelClass.IsDatabaseView)
- segments.Add($"ToView(\"{viewName}\"{schema}{buildAction})");
- else
- segments.Add($"ToTable(\"{tableName}\"{schema}{buildAction})");
+ if (modelClass.ExcludeFromMigrations)
+ modifiers.Add("t.ExcludeFromMigrations();");
+
+ if (modelClass.UseTemporalTables
+ && !modelClass.IsDatabaseView
+ && (!modelClass.Subclasses.Any() || modelClass.ModelRoot.InheritanceStrategy == CodeStrategy.TablePerHierarchy)
+ && modelClass.Superclass == null)
+ modifiers.Add("t.IsTemporal();");
+
+ string buildActions = modifiers.Any()
+ ? $", t => {{ {string.Join(" ", modifiers)} }}"
+ : string.Empty;
+
+ segments.Add(modelClass.IsDatabaseView
+ ? $"ToView(\"{viewName}\"{schema}{buildActions})"
+ : $"ToTable(\"{tableName}\"{schema}{buildActions})");
if (modelClass.Superclass != null)
segments.Add($"HasBaseType<{modelClass.Superclass.FullName}>()");
@@ -101,6 +198,14 @@
&& modelAttribute.Type == "String")
segments.Add($"UseCollation(\"{modelAttribute.DatabaseCollation.Trim('"')}\")");
+ int index = segments.IndexOf("IsRequired()");
+
+ if (index >= 0)
+ {
+ segments.RemoveAt(index);
+ segments.Add("IsRequired()");
+ }
+
return segments;
}
@@ -170,7 +275,10 @@
visited.Add(association);
List segments = new List();
- string separator = sourceInstance.ModelRoot.ShadowKeyNamePattern == ShadowKeyPattern.TableColumn ? string.Empty : "_";
+
+ string separator = sourceInstance.ModelRoot.ShadowKeyNamePattern == ShadowKeyPattern.TableColumn
+ ? string.Empty
+ : "_";
switch (association.TargetMultiplicity) // realized by property on source
{
@@ -297,8 +405,7 @@
visited.Add(association);
List segments = new List();
- bool sourceRequired = false;
- bool targetRequired = false;
+ bool required = false;
segments.Add($"modelBuilder.Entity<{modelClass.FullName}>()");
@@ -307,18 +414,12 @@
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
{
segments.Add($"HasMany<{association.Target.FullName}>(p => p.{association.TargetPropertyName})");
+ required = association.SourceMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One;
break;
}
case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- {
- segments.Add($"HasOne<{association.Target.FullName}>(p => p.{association.TargetPropertyName})");
- targetRequired = true;
-
- break;
- }
-
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
{
segments.Add($"HasOne<{association.Target.FullName}>(p => p.{association.TargetPropertyName})");
@@ -330,67 +431,31 @@
switch (association.SourceMultiplicity) // realized by property on target, but no property on target
{
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
+ segments.Add($"WithMany(p => p.{association.SourcePropertyName})");
+
+ if (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany)
{
- segments.Add($"WithMany(p => p.{association.SourcePropertyName})");
+ ModelClass associationClass = modelClass.Store.ElementDirectory.AllElements.OfType().FirstOrDefault(m => m.DescribedAssociationElementId == association.Id);
- if (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany)
+ if (associationClass == null)
+ segments.AddRange(WriteStandardBidirectionalAssociation(association, foreignKeyColumns, required));
+ else
{
- string tableMap = string.IsNullOrEmpty(association.JoinTableName)
- ? $"{association.Target.Name}_{association.SourcePropertyName}_x_{association.Source.Name}_{association.TargetPropertyName}"
- : association.JoinTableName;
-
- segments.Add($"UsingEntity(x => x.ToTable(\"{tableMap.Trim('"')}\"))");
+ OutputNoTerminator(segments);
+ WriteBidirectionalAssociationWithAssociationClass(modelClass, associationClass, association);
}
-
- break;
}
- case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- {
- segments.Add($"WithOne(p => p.{association.SourcePropertyName})");
- sourceRequired = true;
-
- break;
- }
+ break;
+ case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
segments.Add($"WithOne(p => p.{association.SourcePropertyName})");
break;
}
- string foreignKeySegment = CreateForeignKeySegment(association, foreignKeyColumns);
-
- if (!string.IsNullOrEmpty(foreignKeySegment))
- segments.Add(foreignKeySegment);
-
- if (association.Dependent == association.Target)
- {
- if (association.SourceDeleteAction == DeleteAction.None)
- segments.Add("OnDelete(DeleteBehavior.NoAction)");
- else if (association.SourceDeleteAction == DeleteAction.Cascade)
- segments.Add("OnDelete(DeleteBehavior.Cascade)");
-
- if (targetRequired)
- segments.Add("IsRequired()");
- }
- else if (association.Dependent == association.Source)
- {
- if (association.TargetDeleteAction == DeleteAction.None)
- segments.Add("OnDelete(DeleteBehavior.NoAction)");
- else if (association.TargetDeleteAction == DeleteAction.Cascade)
- segments.Add("OnDelete(DeleteBehavior.Cascade)");
-
- if (sourceRequired)
- segments.Add("IsRequired()");
- }
-
- Output(segments);
-
- if (association.Principal == association.Target && targetRequired)
- Output($"modelBuilder.Entity<{association.Source.FullName}>().Navigation(e => e.{association.TargetPropertyName}).IsRequired();");
- else if (association.Principal == association.Source && sourceRequired)
- Output($"modelBuilder.Entity<{association.Target.FullName}>().Navigation(e => e.{association.SourcePropertyName}).IsRequired();");
+ if (segments.Any()) Output(segments);
if (association.TargetAutoInclude)
Output($"modelBuilder.Entity<{association.Source.FullName}>().Navigation(e => e.{association.TargetPropertyName}).AutoInclude();");
@@ -400,19 +465,11 @@
if (!association.TargetAutoProperty)
{
segments.Add($"modelBuilder.Entity<{association.Source.FullName}>().Navigation(e => e.{association.TargetPropertyName})");
+ segments.Add($"HasField(\"{association.TargetBackingFieldName}\")");
- if (association.Source == association.Principal)
- {
- segments.Add($"HasField(\"{association.TargetBackingFieldName}\")");
- segments.Add($"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode});");
- }
- else if (association.Target == association.Principal)
- {
- segments.Add($"HasField(\"{association.TargetBackingFieldName}\")");
- segments.Add($"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode});");
- }
- else
- segments.Add($"HasField(\"{association.TargetBackingFieldName}\");");
+ segments.Add(modelClass.ModelRoot.IsEFCore6Plus
+ ? $"UsePropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode})"
+ : $"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode})");
Output(segments);
}
@@ -420,26 +477,140 @@
if (!association.SourceAutoProperty)
{
segments.Add($"modelBuilder.Entity<{association.Target.FullName}>().Navigation(e => e.{association.SourcePropertyName})");
+ segments.Add($"HasField(\"{association.SourceBackingFieldName}\")");
- if (association.Target == association.Principal)
- {
- segments.Add($"HasField(\"{association.SourceBackingFieldName}\")");
- segments.Add($"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.SourcePropertyAccessMode});");
- }
- else if (association.Source == association.Principal)
- {
- segments.Add($"HasField(\"{association.SourceBackingFieldName}\")");
- segments.Add($"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.SourcePropertyAccessMode});");
- }
- else
- segments.Add($"HasField(\"{association.SourceBackingFieldName}\");");
+ segments.Add(modelClass.ModelRoot.IsEFCore6Plus
+ ? $"UsePropertyAccessMode(PropertyAccessMode.{association.SourcePropertyAccessMode})"
+ : $"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.SourcePropertyAccessMode})");
Output(segments);
}
-
}
}
+ private IEnumerable WriteStandardBidirectionalAssociation(BidirectionalAssociation association, List foreignKeyColumns, bool required)
+ {
+ List segments = new List();
+
+ string tableMap = string.IsNullOrEmpty(association.JoinTableName)
+ ? $"{association.Target.Name}_{association.SourcePropertyName}_x_{association.Source.Name}_{association.TargetPropertyName}"
+ : association.JoinTableName;
+
+ segments.Add($"UsingEntity(x => x.ToTable(\"{tableMap}\"))");
+
+ string foreignKeySegment = CreateForeignKeySegment(association, foreignKeyColumns);
+
+ if (!string.IsNullOrEmpty(foreignKeySegment))
+ segments.Add(foreignKeySegment);
+
+ WriteSourceDeleteBehavior(association, segments);
+ WriteTargetDeleteBehavior(association, segments);
+
+ if (required
+ && (association.SourceMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One
+ || association.TargetMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One))
+ segments.Add("IsRequired()");
+
+ return segments;
+ }
+
+ private void WriteBidirectionalAssociationWithAssociationClass(ModelClass modelClass, ModelClass associationClass, BidirectionalAssociation association)
+ {
+ string indent = associationClass.ModelRoot.UseTabs
+ ? "\t"
+ : " ";
+ BidirectionalAssociation associationToSource = (BidirectionalAssociation)associationClass.AllNavigationProperties().First(n => n.AssociationObject.Source == association.Source).AssociationObject;
+ BidirectionalAssociation associationToTarget = (BidirectionalAssociation)associationClass.AllNavigationProperties().First(n => n.AssociationObject.Source == association.Target).AssociationObject;
+
+ if (modelClass.ModelRoot.ChopMethodChains)
+ PushIndent(" ");
+ else
+ PushIndent(indent);
+
+ Output($".UsingEntity<{associationClass.FullName}>(");
+ PushIndent(indent);
+ Output("j => j");
+ PushIndent(indent);
+ Output($".HasOne(x => x.{associationToTarget.SourcePropertyName})");
+ Output($".WithMany(x => x.{associationToTarget.TargetPropertyName})");
+ Output($".HasForeignKey(x => x.{associationClass.Attributes.First(a => a.IsForeignKeyFor == associationToTarget.Id).Name}),");
+ PopIndent();
+ Output("j => j");
+ PushIndent(indent);
+ Output($".HasOne(x => x.{associationToSource.SourcePropertyName})");
+ Output($".WithMany(x => x.{associationToSource.TargetPropertyName})");
+ Output($".HasForeignKey(x => x.{associationClass.Attributes.First(a => a.IsForeignKeyFor == associationToSource.Id).Name}),");
+ PopIndent();
+ Output("j =>");
+ Output("{");
+
+ #region transient properties
+
+ foreach (ModelAttribute transient in associationClass.Attributes.Where(x => !x.Persistent))
+ Output($"j.Ignore(t => t.{transient.Name});");
+
+ #endregion
+
+ #region table definition
+
+ string tableName = string.IsNullOrEmpty(associationClass.TableName)
+ ? associationClass.Name
+ : associationClass.TableName;
+
+ string schema = string.IsNullOrEmpty(associationClass.DatabaseSchema) || associationClass.DatabaseSchema == associationClass.ModelRoot.DatabaseSchema
+ ? string.Empty
+ : $", \"{associationClass.DatabaseSchema}\"";
+
+ List modifiers = new List();
+
+ if (associationClass.UseTemporalTables)
+ modifiers.Add(" t.IsTemporal();");
+
+ string buildActions = modifiers.Any()
+ ? $", t => {{ {string.Join(" ", modifiers)} }}"
+ : string.Empty;
+
+ Output($"j.ToTable(\"{tableName}\"{schema}{buildActions});");
+
+ List identityAttributes = associationClass.IdentityAttributes.ToList();
+
+ if (identityAttributes.Count == 1)
+ Output($"j.HasKey(t => t.{identityAttributes[0].Name});");
+ else if (identityAttributes.Count > 1)
+ Output($"j.HasKey(t => new {{ t.{string.Join(", t.", identityAttributes.Select(ia => ia.Name))} }});");
+
+ #endregion
+
+#region model attributes
+
+ foreach (ModelAttribute modelAttribute in associationClass.Attributes.Where(x => x.Persistent && !x.IsIdentity))
+ {
+ List buffer = new List();
+ buffer.AddRange(GatherModelAttributeSegments(modelAttribute));
+
+ if (buffer.Any())
+ Output($"j.Property(t => t.{modelAttribute.Name}).{string.Join(".", buffer)};");
+
+ if (modelAttribute.Indexed)
+ {
+ buffer.Clear();
+ buffer.Add($"HasIndex(t => t.{modelAttribute.Name})");
+
+ if (modelAttribute.IndexedUnique)
+ buffer.Add("IsUnique()");
+
+ Output($"j.{string.Join(".", buffer)};");
+ }
+ }
+
+#endregion
+
+ PopIndent();
+ Output("});");
+ PopIndent();
+ PopIndent();
+ }
+
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
protected override void ConfigureUnidirectionalAssociations(ModelClass modelClass
, List visited
@@ -463,7 +634,10 @@
visited.Add(association);
List segments = new List();
- string separator = sourceInstance.ModelRoot.ShadowKeyNamePattern == ShadowKeyPattern.TableColumn ? string.Empty : "_";
+
+ string separator = sourceInstance.ModelRoot.ShadowKeyNamePattern == ShadowKeyPattern.TableColumn
+ ? string.Empty
+ : "_";
switch (association.TargetMultiplicity) // realized by property on source
{
@@ -553,8 +727,7 @@
visited.Add(association);
List segments = new List();
- bool sourceRequired = false;
- bool targetRequired = false;
+ bool required = false;
segments.Add($"modelBuilder.Entity<{modelClass.FullName}>()");
@@ -562,15 +735,11 @@
{
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
segments.Add($"HasMany<{association.Target.FullName}>(p => p.{association.TargetPropertyName})");
+ required = (association.SourceMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One);
break;
case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- segments.Add($"HasOne<{association.Target.FullName}>(p => p.{association.TargetPropertyName})");
- targetRequired = true;
-
- break;
-
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
segments.Add($"HasOne<{association.Target.FullName}>(p => p.{association.TargetPropertyName})");
@@ -581,6 +750,7 @@
{
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
segments.Add("WithMany()");
+ required = (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One);
if (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany)
{
@@ -594,11 +764,6 @@
break;
case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- segments.Add("WithOne()");
- sourceRequired = true;
-
- break;
-
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
segments.Add("WithOne()");
@@ -616,9 +781,6 @@
segments.Add("OnDelete(DeleteBehavior.NoAction)");
else if (association.SourceDeleteAction == DeleteAction.Cascade)
segments.Add("OnDelete(DeleteBehavior.Cascade)");
-
- if (targetRequired)
- segments.Add("IsRequired()");
}
else if (association.Dependent == association.Source)
{
@@ -626,15 +788,12 @@
segments.Add("OnDelete(DeleteBehavior.NoAction)");
else if (association.TargetDeleteAction == DeleteAction.Cascade)
segments.Add("OnDelete(DeleteBehavior.Cascade)");
-
- if (sourceRequired)
- segments.Add("IsRequired()");
}
- Output(segments);
+ if (required)
+ segments.Add("IsRequired()");
- if (association.Principal == association.Target && targetRequired)
- Output($"modelBuilder.Entity<{association.Source.FullName}>().Navigation(e => e.{association.TargetPropertyName}).IsRequired();");
+ Output(segments);
if (association.TargetAutoInclude)
Output($"modelBuilder.Entity<{association.Source.FullName}>().Navigation(e => e.{association.TargetPropertyName}).AutoInclude();");
@@ -643,18 +802,9 @@
{
segments.Add($"modelBuilder.Entity<{association.Source.FullName}>().Navigation(e => e.{association.TargetPropertyName})");
- if (association.Source == association.Principal)
- {
- segments.Add($"HasField(\"{association.TargetBackingFieldName}\")");
- segments.Add($"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode});");
- }
- else if (association.Target == association.Principal)
- {
- segments.Add($"HasField(\"{association.TargetBackingFieldName}\")");
- segments.Add($"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode});");
- }
- else
- segments.Add($"HasField(\"{association.TargetBackingFieldName}\");");
+ segments.Add(modelClass.ModelRoot.IsEFCore6Plus
+ ? $"UsePropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode})"
+ : $"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode})");
Output(segments);
}
diff --git a/src/DslPackage/TextTemplates/EFCoreDesigner.ttinclude b/src/DslPackage/TextTemplates/EFCoreDesigner.ttinclude
index 3a3a235e0..7a297cbdc 100644
--- a/src/DslPackage/TextTemplates/EFCoreDesigner.ttinclude
+++ b/src/DslPackage/TextTemplates/EFCoreDesigner.ttinclude
@@ -23,7 +23,7 @@
#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
-// EFDesigner v3.1.0.0
+// EFDesigner v4.1.2.0
// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
diff --git a/src/DslPackage/TextTemplates/EFCoreModelGenerator.ttinclude b/src/DslPackage/TextTemplates/EFCoreModelGenerator.ttinclude
index 8dba2a64a..0f44709f4 100644
--- a/src/DslPackage/TextTemplates/EFCoreModelGenerator.ttinclude
+++ b/src/DslPackage/TextTemplates/EFCoreModelGenerator.ttinclude
@@ -23,7 +23,7 @@
#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
- // EFDesigner v3.1.0.0
+ // EFDesigner v4.1.2.0
// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
@@ -136,7 +136,7 @@
Output("}");
Output("}");
NL();
-
+
Output("/// ");
Output("/// Defines a factory for creating derived DbContext instances.");
Output("/// ");
@@ -193,79 +193,87 @@
return result;
}
- protected virtual void ConfigureModelClasses(List segments, ModelClass[] classesWithTables, List foreignKeyColumns, List visited)
+ protected virtual void ConfigureModelClass(List segments, ModelClass[] classesWithTables, List foreignKeyColumns, List visited, ModelClass modelClass)
{
- foreach (ModelClass modelClass in modelRoot.Classes.OrderBy(x => x.Name))
- {
- segments.Clear();
- foreignKeyColumns.Clear();
- NL();
+ segments.Clear();
+ foreignKeyColumns.Clear();
+ NL();
- if (modelClass.IsDependentType)
- {
- segments.Add($"modelBuilder.Owned<{modelClass.FullName}>()");
- Output(segments);
- continue;
- }
+ if (modelClass.IsDependentType)
+ {
+ segments.Add($"modelBuilder.Owned<{modelClass.FullName}>()");
+ Output(segments);
+ return;
+ }
- segments.Add($"modelBuilder.Entity<{modelClass.FullName}>()");
+ segments.Add($"modelBuilder.Entity<{modelClass.FullName}>()");
- foreach (ModelAttribute transient in modelClass.Attributes.Where(x => !x.Persistent))
- segments.Add($"Ignore(t => t.{transient.Name})");
+ ConfigureTransientProperties(segments, modelClass);
- //if (modelRoot.InheritanceStrategy == CodeStrategy.TablePerConcreteType && modelClass.Superclass != null)
- // segments.Add("Map(x => x.MapInheritedProperties())");
+ //if (modelRoot.InheritanceStrategy == CodeStrategy.TablePerConcreteType && modelClass.Superclass != null)
+ // segments.Add("Map(x => x.MapInheritedProperties())");
- if (classesWithTables.Contains(modelClass))
+ if (classesWithTables.Contains(modelClass))
+ {
+ if (modelClass.IsQueryType)
{
- if (modelClass.IsQueryType)
- {
- Output($"// There is no storage defined for {modelClass.Name} because its IsQueryType value is");
- Output($"// set to 'true'. Please provide the {modelRoot.FullName}.Get{modelClass.Name}SqlQuery() method in the partial class.");
- Output("// ");
- Output($"// private string Get{modelClass.Name}SqlQuery()");
- Output("// {");
- Output($"// return the defining SQL query that pulls all the properties for {modelClass.FullName}");
- Output("// }");
-
- segments.Add($"ToSqlQuery(Get{modelClass.Name}SqlQuery())");
- }
- else
- ConfigureTable(segments, modelClass);
+ Output($"// There is no storage defined for {modelClass.Name} because its IsQueryType value is");
+ Output($"// set to 'true'. Please provide the {modelRoot.FullName}.Get{modelClass.Name}SqlQuery() method in the partial class.");
+ Output("// ");
+ Output($"// private string Get{modelClass.Name}SqlQuery()");
+ Output("// {");
+ Output($"// return the defining SQL query that pulls all the properties for {modelClass.FullName}");
+ Output("// }");
+
+ segments.Add($"ToSqlQuery(Get{modelClass.Name}SqlQuery())");
}
+ else
+ ConfigureTable(segments, modelClass);
+ }
- if (segments.Count > 1 || modelClass.IsDependentType)
- Output(segments);
+ if (segments.Count > 1 || modelClass.IsDependentType)
+ Output(segments);
- // attribute level
- ConfigureModelAttributes(segments, modelClass);
+ // attribute level
+ ConfigureModelAttributes(segments, modelClass);
- bool hasDefinedConcurrencyToken = modelClass.AllAttributes.Any(x => x.IsConcurrencyToken);
+ bool hasDefinedConcurrencyToken = modelClass.AllAttributes.Any(x => x.IsConcurrencyToken);
- if (!hasDefinedConcurrencyToken && modelClass.EffectiveConcurrency == ConcurrencyOverride.Optimistic)
- Output($@"modelBuilder.Entity<{modelClass.FullName}>().Property(""Timestamp"").IsConcurrencyToken();");
+ if (!hasDefinedConcurrencyToken && modelClass.EffectiveConcurrency == ConcurrencyOverride.Optimistic)
+ Output($@"modelBuilder.Entity<{modelClass.FullName}>().Property(""Timestamp"").IsConcurrencyToken();");
- // Navigation endpoints are distingished as Source and Target. They are also distinguished as Principal
- // and Dependent. So how do these map to each other? Short answer: they don't - they're orthogonal concepts.
- // Source and Target are accidents of where the user started drawing the association, and help define where the
- // properties are in unidirectional associations. Principal and Dependent define where the foreign keys go in
- // the persistence mechanism.
+ // Navigation endpoints are distingished as Source and Target. They are also distinguished as Principal
+ // and Dependent. So how do these map to each other? Short answer: they don't - they're orthogonal concepts.
+ // Source and Target are accidents of where the user started drawing the association, and help define where the
+ // properties are in unidirectional associations. Principal and Dependent define where the foreign keys go in
+ // the persistence mechanism.
- // What matters to code generation is the Principal and Dependent classifications, so we focus on those.
- // In the case of 1-1 or 0/1-0/1, it's situational, so the user has to tell us.
- // In all other cases, we can tell by the cardinalities of the associations.
+ // What matters to code generation is the Principal and Dependent classifications, so we focus on those.
+ // In the case of 1-1 or 0/1-0/1, it's situational, so the user has to tell us.
+ // In all other cases, we can tell by the cardinalities of the associations.
- // navigation properties
- List declaredShadowProperties = new List();
+ // navigation properties
+ List declaredShadowProperties = new List();
- if (!modelClass.IsDependentType)
- {
- ConfigureUnidirectionalAssociations(modelClass, visited, foreignKeyColumns, declaredShadowProperties);
- ConfigureBidirectionalAssociations(modelClass, visited, foreignKeyColumns, declaredShadowProperties);
- }
+ if (!modelClass.IsDependentType)
+ {
+ ConfigureUnidirectionalAssociations(modelClass, visited, foreignKeyColumns, declaredShadowProperties);
+ ConfigureBidirectionalAssociations(modelClass, visited, foreignKeyColumns, declaredShadowProperties);
}
}
+ protected virtual void ConfigureModelClasses(List segments, ModelClass[] classesWithTables, List foreignKeyColumns, List visited)
+ {
+ foreach (ModelClass modelClass in modelRoot.Classes.OrderBy(x => x.Name))
+ ConfigureModelClass(segments, classesWithTables, foreignKeyColumns, visited, modelClass);
+ }
+
+ protected static void ConfigureTransientProperties(List segments, ModelClass modelClass)
+ {
+ foreach (ModelAttribute transient in modelClass.Attributes.Where(x => !x.Persistent))
+ segments.Add($"Ignore(t => t.{transient.Name})");
+ }
+
protected virtual void ConfigureTable(List segments, ModelClass modelClass)
{
string tableName = string.IsNullOrEmpty(modelClass.TableName) ? modelClass.Name : modelClass.TableName;
@@ -574,106 +582,106 @@
switch (association.TargetMultiplicity) // realized by property on source
{
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
- {
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add($"ToTable(\"{(string.IsNullOrEmpty(association.Target.TableName) ? association.Target.Name : association.Target.TableName)}\")");
- Output(segments);
+ {
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add($"ToTable(\"{(string.IsNullOrEmpty(association.Target.TableName) ? association.Target.Name : association.Target.TableName)}\")");
+ Output(segments);
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add($"WithOwner(\"{association.SourcePropertyName}\")");
- segments.Add($"HasForeignKey(\"{association.SourcePropertyName}{separator}Id\")");
- Output(segments);
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add($"WithOwner(\"{association.SourcePropertyName}\")");
+ segments.Add($"HasForeignKey(\"{association.SourcePropertyName}{separator}Id\")");
+ Output(segments);
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add($"Property<{modelRoot.DefaultIdentityType}>(\"Id\")");
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add($"Property<{modelRoot.DefaultIdentityType}>(\"Id\")");
- Output(segments);
+ Output(segments);
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add("HasKey(\"Id\")");
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add("HasKey(\"Id\")");
- Output(segments);
+ Output(segments);
- WriteBidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsMany(p => p.{association.TargetPropertyName})", visited);
+ WriteBidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsMany(p => p.{association.TargetPropertyName})", visited);
- break;
- }
+ break;
+ }
case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- {
- segments.Add(baseSegment);
- segments.Add($"OwnsOne(p => p.{association.TargetPropertyName})");
- segments.Add($"WithOwner(p => p.{association.SourcePropertyName})");
- Output(segments);
-
- if (!string.IsNullOrEmpty(association.Target.TableName))
{
segments.Add(baseSegment);
segments.Add($"OwnsOne(p => p.{association.TargetPropertyName})");
- segments.Add($"ToTable(\"{association.Target.TableName}\")");
+ segments.Add($"WithOwner(p => p.{association.SourcePropertyName})");
Output(segments);
- }
- foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
- {
- segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
+ if (!string.IsNullOrEmpty(association.Target.TableName))
+ {
+ segments.Add(baseSegment);
+ segments.Add($"OwnsOne(p => p.{association.TargetPropertyName})");
+ segments.Add($"ToTable(\"{association.Target.TableName}\")");
+ Output(segments);
+ }
- if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
- segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
+ foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
+ {
+ segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
- if (modelAttribute.Required)
- segments.Add("IsRequired()");
+ if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
+ segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
- if (segments.Count > 1)
- Output(segments);
+ if (modelAttribute.Required)
+ segments.Add("IsRequired()");
- segments.Clear();
- }
+ if (segments.Count > 1)
+ Output(segments);
- WriteBidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
+ segments.Clear();
+ }
- break;
- }
+ WriteBidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
- case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
- {
- segments.Add(baseSegment);
- segments.Add($"OwnsOne(p => p.{association.TargetPropertyName})");
- segments.Add($"WithOwner(p => p.{association.SourcePropertyName})");
- Output(segments);
+ break;
+ }
- if (!string.IsNullOrEmpty(association.Target.TableName))
+ case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
{
segments.Add(baseSegment);
segments.Add($"OwnsOne(p => p.{association.TargetPropertyName})");
- segments.Add($"ToTable(\"{association.Target.TableName}\")");
+ segments.Add($"WithOwner(p => p.{association.SourcePropertyName})");
Output(segments);
- }
- foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
- {
- segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
+ if (!string.IsNullOrEmpty(association.Target.TableName))
+ {
+ segments.Add(baseSegment);
+ segments.Add($"OwnsOne(p => p.{association.TargetPropertyName})");
+ segments.Add($"ToTable(\"{association.Target.TableName}\")");
+ Output(segments);
+ }
- if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
- segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
+ foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
+ {
+ segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
- if (modelAttribute.Required)
- segments.Add("IsRequired()");
+ if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
+ segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
- if (segments.Count > 1)
- Output(segments);
+ if (modelAttribute.Required)
+ segments.Add("IsRequired()");
- segments.Clear();
- }
+ if (segments.Count > 1)
+ Output(segments);
- WriteBidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
+ segments.Clear();
+ }
- break;
- }
+ WriteBidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
+
+ break;
+ }
}
}
}
@@ -721,12 +729,12 @@
if (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany)
{
- string tableMap = string.IsNullOrEmpty(association.JoinTableName)
- ? $"{association.Target.Name}_{association.SourcePropertyName}_x_{association.Source.Name}_{association.TargetPropertyName}"
- : association.JoinTableName;
+ string tableMap = string.IsNullOrEmpty(association.JoinTableName)
+ ? $"{association.Target.Name}_{association.SourcePropertyName}_x_{association.Source.Name}_{association.TargetPropertyName}"
+ : association.JoinTableName;
- segments.Add($"UsingEntity(x => x.ToTable(\"{tableMap}\"))");
- }
+ segments.Add($"UsingEntity(x => x.ToTable(\"{tableMap}\"))");
+ }
break;
@@ -742,23 +750,23 @@
break;
}
- string foreignKeySegment = CreateForeignKeySegment(association, foreignKeyColumns);
+ string foreignKeySegment = CreateForeignKeySegment(association, foreignKeyColumns);
- if (!string.IsNullOrEmpty(foreignKeySegment))
- segments.Add(foreignKeySegment);
+ if (!string.IsNullOrEmpty(foreignKeySegment))
+ segments.Add(foreignKeySegment);
- WriteSourceDeleteBehavior(association, segments);
+ WriteSourceDeleteBehavior(association, segments);
- if (required
- && (association.SourceMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One
- || association.TargetMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One))
- segments.Add("IsRequired()");
+ if (required
+ && (association.SourceMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One
+ || association.TargetMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One))
+ segments.Add("IsRequired()");
Output(segments);
}
}
- protected virtual void WriteTargetDeleteBehavior(UnidirectionalAssociation association, List segments)
+ protected virtual void WriteTargetDeleteBehavior(Association association, List segments)
{
if (!association.Source.IsDependentType
&& !association.Target.IsDependentType
@@ -836,69 +844,69 @@
switch (association.TargetMultiplicity) // realized by property on source
{
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
- {
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add($"WithOwner(\"{association.Source.Name}_{association.TargetPropertyName}\")");
- segments.Add($"HasForeignKey(\"{association.Source.Name}_{association.TargetPropertyName}{separator}Id\")");
- Output(segments);
+ {
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add($"WithOwner(\"{association.Source.Name}_{association.TargetPropertyName}\")");
+ segments.Add($"HasForeignKey(\"{association.Source.Name}_{association.TargetPropertyName}{separator}Id\")");
+ Output(segments);
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add($"Property<{modelRoot.DefaultIdentityType}>(\"Id\")");
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add($"Property<{modelRoot.DefaultIdentityType}>(\"Id\")");
- Output(segments);
+ Output(segments);
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add("HasKey(\"Id\")");
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add("HasKey(\"Id\")");
- Output(segments);
+ Output(segments);
- WriteUnidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsMany(p => p.{association.TargetPropertyName})", visited);
+ WriteUnidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsMany(p => p.{association.TargetPropertyName})", visited);
- break;
- }
+ break;
+ }
case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- {
- foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
{
- segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
+ foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
+ {
+ segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
- if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
- segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
+ if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
+ segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
- if (modelAttribute.Required)
- segments.Add("IsRequired()");
+ if (modelAttribute.Required)
+ segments.Add("IsRequired()");
- Output(segments);
- }
+ Output(segments);
+ }
- WriteUnidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
+ WriteUnidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
- break;
- }
+ break;
+ }
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
- {
- foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
{
- segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
+ foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
+ {
+ segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
- if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
- segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
+ if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
+ segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
- if (modelAttribute.Required)
- segments.Add("IsRequired()");
+ if (modelAttribute.Required)
+ segments.Add("IsRequired()");
- Output(segments);
- }
+ Output(segments);
+ }
- WriteUnidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
+ WriteUnidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
- break;
- }
+ break;
+ }
}
}
}
diff --git a/src/DslPackage/TextTemplates/EFDesigner.ttinclude b/src/DslPackage/TextTemplates/EFDesigner.ttinclude
index 87d6d5f23..75a6068cf 100644
--- a/src/DslPackage/TextTemplates/EFDesigner.ttinclude
+++ b/src/DslPackage/TextTemplates/EFDesigner.ttinclude
@@ -23,7 +23,7 @@
#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
- // EFDesigner v3.1.0.0
+ // EFDesigner v4.1.2.0
// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
diff --git a/src/DslPackage/TextTemplates/EFModelFileManager.ttinclude b/src/DslPackage/TextTemplates/EFModelFileManager.ttinclude
index fc3b8f06f..a31c4b390 100644
--- a/src/DslPackage/TextTemplates/EFModelFileManager.ttinclude
+++ b/src/DslPackage/TextTemplates/EFModelFileManager.ttinclude
@@ -23,7 +23,7 @@
#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
- // EFDesigner v3.1.0.0
+ // EFDesigner v4.1.2.0
// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
@@ -208,7 +208,7 @@
private void CheckoutFileIfRequired(string fileName)
{
- SourceControl sc = dte.SourceControl;
+ EnvDTE.SourceControl sc = dte.SourceControl;
if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName))
sc.CheckOutItem(fileName);
diff --git a/src/DslPackage/TextTemplates/EFModelGenerator.ttinclude b/src/DslPackage/TextTemplates/EFModelGenerator.ttinclude
index 668f9f119..0ccd6b244 100644
--- a/src/DslPackage/TextTemplates/EFModelGenerator.ttinclude
+++ b/src/DslPackage/TextTemplates/EFModelGenerator.ttinclude
@@ -23,7 +23,7 @@
#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
- // EFDesigner v3.1.0.0
+ // EFDesigner v4.1.2.0
// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
@@ -42,6 +42,16 @@
segments.Clear();
}
+ protected void OutputNoTerminator(List segments)
+ {
+ if (ModelRoot.ChopMethodChains)
+ OutputChoppedNoTerminator(segments);
+ else
+ Output(string.Join(".", segments));
+
+ segments.Clear();
+ }
+
protected void Output(string text)
{
if (text == "}")
@@ -90,6 +100,34 @@
segments.Clear();
}
+ protected void OutputChoppedNoTerminator(List segments)
+ {
+ string[] segmentArray = segments?.ToArray() ?? new string[0];
+
+ if (!segmentArray.Any())
+ return;
+
+ int indent = segmentArray[0].IndexOf('.');
+
+ if (indent == -1)
+ {
+ if (segmentArray.Length > 1)
+ {
+ segmentArray[0] = $"{segmentArray[0]}.{segmentArray[1]}";
+ indent = segmentArray[0].IndexOf('.');
+ segmentArray = segmentArray.Where((source, index) => index != 1).ToArray();
+ }
+ }
+
+ for (int index = 1; index < segmentArray.Length; ++index)
+ segmentArray[index] = $"{new string(' ', indent)}.{segmentArray[index]}";
+
+ foreach (string segment in segmentArray)
+ Output(segment);
+
+ segments.Clear();
+ }
+
public abstract class EFModelGenerator
{
protected static string[] xmlDocTags =
@@ -150,8 +188,11 @@
// implementations delegated to the surrounding GeneratedTextTransformation for backward compatability
protected void NL() { host.NL(); }
protected void Output(List segments) { host.Output(segments); }
+ protected void OutputNoTerminator(List segments) { host.OutputNoTerminator(segments); }
protected void Output(string text) { host.Output(text); }
protected void Output(string template, params object[] items) { host.Output(template, items); }
+ protected void PushIndent(string indent) { host.PushIndent(indent); }
+ protected void PopIndent() { host.PopIndent(); }
protected void ClearIndent() { host.ClearIndent(); }
public static string[] NonNullableTypes
@@ -289,10 +330,10 @@
}
if (!string.IsNullOrWhiteSpace(modelAttribute.DisplayText))
- Output($"[Display(Name=\"{modelAttribute.DisplayText.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.DataAnnotations.Display(Name=\"{modelAttribute.DisplayText.Replace("\"", "\\\"")}\")]");
if (!string.IsNullOrWhiteSpace(modelAttribute.Summary))
- Output($"[System.ComponentModel.Description(\"{modelAttribute.Summary.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.Description(\"{modelAttribute.Summary.Trim('\r', '\n').Replace("\"", "\\\"")}\")]");
}
protected abstract List GetAdditionalUsingStatements();
@@ -373,7 +414,8 @@
nsParts.Add("Migrations");
return string.Join(".", nsParts);
- } protected List GetRequiredParameterNames(ModelClass modelClass, bool publicOnly = false)
+ }
+ protected List GetRequiredParameterNames(ModelClass modelClass, bool publicOnly = false)
{
return GetRequiredParameters(modelClass, null, publicOnly).Select(p => p.Split(' ')[1]).ToList();
}
@@ -490,7 +532,7 @@
Output($"[{modelClass.CustomAttributes.Trim('[', ']')}]");
if (!string.IsNullOrWhiteSpace(modelClass.Summary))
- Output($"[System.ComponentModel.Description(\"{modelClass.Summary.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.Description(\"{modelClass.Summary.Trim('\r', '\n').Replace("\"", "\\\"")}\")]");
Output(baseClass.Length > 0
? $"public {isAbstract}partial class {modelClass.Name}: {baseClass}"
@@ -515,7 +557,7 @@
if (!string.IsNullOrEmpty(comment))
{
int chunkSize = 80;
- string[] parts = comment.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.RemoveEmptyEntries);
+ string[] parts = comment.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string value in parts)
{
@@ -547,7 +589,7 @@
protected void WriteCommentBody(string comment)
{
foreach (string s in GenerateCommentBody(comment))
- Output($"/// {s}");
+ Output($"/// {s}");
}
protected void WriteConstructor(ModelClass modelClass)
@@ -685,7 +727,11 @@
else if (requiredAttribute.Type.StartsWith("Geo"))
Output($"if ({requiredAttribute.Name.ToLower()} == null) throw new ArgumentNullException(nameof({requiredAttribute.Name.ToLower()}));");
- Output($"this.{requiredAttribute.Name} = {requiredAttribute.Name.ToLower()};");
+ string lhs = requiredAttribute.AutoProperty || string.IsNullOrEmpty(requiredAttribute.BackingFieldName)
+ ? requiredAttribute.Name
+ : requiredAttribute.BackingFieldName;
+
+ Output($"this.{lhs} = {requiredAttribute.Name.ToLower()};");
NL();
}
@@ -703,9 +749,13 @@
if (modelAttribute.Type == "decimal")
initialValue += "m";
+ string lhs = modelAttribute.AutoProperty || string.IsNullOrEmpty(modelAttribute.BackingFieldName)
+ ? modelAttribute.Name
+ : modelAttribute.BackingFieldName;
+
Output(quote.Length > 0
- ? $"this.{modelAttribute.Name} = {quote}{FullyQualified(initialValue.Trim(quote[0]))}{quote};"
- : $"this.{modelAttribute.Name} = {quote}{FullyQualified(initialValue)}{quote};");
+ ? $"this.{lhs} = {quote}{FullyQualified(initialValue.Trim(quote[0]))}{quote};"
+ : $"this.{lhs} = {quote}{FullyQualified(initialValue)}{quote};");
}
// all required navigation properties that aren't a 1..1 relationship
@@ -717,17 +767,21 @@
string parameterName = requiredNavigationProperty.PropertyName.ToLower();
Output($"if ({parameterName} == null) throw new ArgumentNullException(nameof({parameterName}));");
+ string targetObjectName = requiredNavigationProperty.IsAutoProperty
+ ? requiredNavigationProperty.PropertyName
+ : requiredNavigationProperty.BackingFieldName;
+
if (!requiredNavigationProperty.ConstructorParameterOnly)
{
Output(requiredNavigationProperty.IsCollection
- ? $"{requiredNavigationProperty.PropertyName}.Add({parameterName});"
- : $"this.{requiredNavigationProperty.PropertyName} = {parameterName};");
+ ? $"this.{targetObjectName}.Add({parameterName});"
+ : $"this.{targetObjectName} = {parameterName};");
}
if (!string.IsNullOrEmpty(otherSide.PropertyName))
{
- Output(otherSide.IsCollection
- ? $"{parameterName}.{otherSide.PropertyName}.Add(this);"
+ Output(otherSide.IsCollection
+ ? $"{parameterName}.{otherSide.PropertyName}.Add(this);"
: $"{parameterName}.{otherSide.PropertyName} = this;");
}
@@ -852,9 +906,13 @@
if (modelAttribute.Type == "decimal")
initialValue += "m";
+ string lhs = modelAttribute.AutoProperty || string.IsNullOrEmpty(modelAttribute.BackingFieldName)
+ ? modelAttribute.Name
+ : modelAttribute.BackingFieldName;
+
Output(quote.Length == 1
- ? $"{modelAttribute.Name} = {quote}{FullyQualified(initialValue.Trim(quote[0]))}{quote};"
- : $"{modelAttribute.Name} = {quote}{FullyQualified(initialValue)}{quote};");
+ ? $"{lhs} = {quote}{FullyQualified(initialValue.Trim(quote[0]))}{quote};"
+ : $"{lhs} = {quote}{FullyQualified(initialValue)}{quote};");
++lineCount;
}
@@ -895,7 +953,7 @@
Output($"[{modelEnum.CustomAttributes.Trim('[', ']')}]");
if (!string.IsNullOrWhiteSpace(modelEnum.Summary))
- Output($"[System.ComponentModel.Description(\"{modelEnum.Summary.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.Description(\"{modelEnum.Summary.Trim('\r', '\n').Replace("\"", "\\\"")}\")]");
Output($"public enum {modelEnum.Name} : {modelEnum.ValueType}");
Output("{");
@@ -922,10 +980,10 @@
Output($"[{values[index].CustomAttributes.Trim('[', ']')}]");
if (!string.IsNullOrWhiteSpace(values[index].Summary))
- Output($"[System.ComponentModel.Description(\"{values[index].Summary.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.Description(\"{values[index].Summary.Trim('\r', '\n').Replace("\"", "\\\"")}\")]");
if (!string.IsNullOrWhiteSpace(values[index].DisplayText))
- Output($"[System.ComponentModel.DataAnnotations.Display(Name=\"{values[index].DisplayText.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.DataAnnotations.Display(Name=\"{values[index].DisplayText.Trim('\r', '\n').Replace("\"", "\\\"")}\")]");
Output(string.IsNullOrEmpty(values[index].Value)
? $"{values[index].Name}{(index < values.Length - 1 ? "," : string.Empty)}"
@@ -948,7 +1006,7 @@
Output(" *************************************************************************/");
NL();
- foreach (NavigationProperty navigationProperty in modelClass.LocalNavigationProperties().Where(x => !x.ConstructorParameterOnly))
+ foreach (NavigationProperty navigationProperty in modelClass.LocalNavigationProperties().Where(x => !x.ConstructorParameterOnly).OrderBy(x => x.PropertyName))
{
string type = navigationProperty.IsCollection
? $"ICollection<{navigationProperty.ClassType.FullName}>"
@@ -1015,10 +1073,10 @@
Output($"[{navigationProperty.CustomAttributes.Trim('[', ']')}]");
if (!string.IsNullOrWhiteSpace(navigationProperty.Summary))
- Output($"[Description(\"{navigationProperty.Summary.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.Description(\"{navigationProperty.Summary.Replace("\"", "\\\"")}\")]");
if (!string.IsNullOrWhiteSpace(navigationProperty.DisplayText))
- Output($"[Display(Name=\"{navigationProperty.DisplayText.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.DataAnnotations.Display(Name=\"{navigationProperty.DisplayText.Replace("\"", "\\\"")}\")]");
if (navigationProperty.IsAutoProperty)
{
@@ -1053,7 +1111,7 @@
Output("}");
Output("set");
Output("{");
- Output($"{type} oldValue = {navigationProperty.BackingFieldName};");
+ Output($"{type} oldValue = {navigationProperty.PropertyName};");
Output($"Set{navigationProperty.PropertyName}(oldValue, ref value);");
Output("if (oldValue != value)");
Output("{");
@@ -1080,7 +1138,7 @@
List segments = new List();
- foreach (ModelAttribute modelAttribute in modelClass.Attributes)
+ foreach (ModelAttribute modelAttribute in modelClass.Attributes.OrderBy(x => x.Name))
{
segments.Clear();
@@ -1185,7 +1243,7 @@
Output("}");
Output($"{setterVisibility}set");
Output("{");
- Output($"{modelAttribute.FQPrimitiveType}{nullable} oldValue = {modelAttribute.BackingFieldName};");
+ Output($"{modelAttribute.FQPrimitiveType}{nullable} oldValue = {modelAttribute.Name};");
Output($"Set{modelAttribute.Name}(oldValue, ref value);");
Output("if (oldValue != value)");
Output("{");
@@ -1208,7 +1266,7 @@
Output("/// ");
Output("/// Concurrency token");
Output("/// ");
- Output("[Timestamp]");
+ Output("[System.ComponentModel.DataAnnotations.Timestamp]");
Output("public Byte[] Timestamp { get; set; }");
NL();
}
diff --git a/src/DslPackage/TextTemplates/EditingOnly/EF6Designer.cs b/src/DslPackage/TextTemplates/EditingOnly/EF6Designer.cs
index c0b85eff8..913940b0b 100644
--- a/src/DslPackage/TextTemplates/EditingOnly/EF6Designer.cs
+++ b/src/DslPackage/TextTemplates/EditingOnly/EF6Designer.cs
@@ -1,6 +1,6 @@
#region Template
-// EFDesigner v3.0.8
-// Copyright (c) 2017-2021 Michael Sawczyn
+// EFDesigner v4.1.2.0
+// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
// This file is only present to support transition between v2.x EFModel templates and v3+ EFModel templates
diff --git a/src/DslPackage/TextTemplates/EditingOnly/EF6ModelGenerator.cs b/src/DslPackage/TextTemplates/EditingOnly/EF6ModelGenerator.cs
index a99f344d6..1262d13ff 100644
--- a/src/DslPackage/TextTemplates/EditingOnly/EF6ModelGenerator.cs
+++ b/src/DslPackage/TextTemplates/EditingOnly/EF6ModelGenerator.cs
@@ -10,8 +10,8 @@ namespace Sawczyn.EFDesigner.EFModel.EditingOnly
public partial class GeneratedTextTransformation
{
#region Template
- // EFDesigner v3.0.8.0
- // Copyright (c) 2017-2021 Michael Sawczyn
+ // EFDesigner v4.1.2.0
+ // Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
public class EF6ModelGenerator : EFModelGenerator
@@ -796,3 +796,5 @@ private void WriteOnModelCreate(ModelClass[] classesWithTables)
#endregion Template
}
}
+
+
diff --git a/src/DslPackage/TextTemplates/EditingOnly/EFCore2ModelGenerator.cs b/src/DslPackage/TextTemplates/EditingOnly/EFCore2ModelGenerator.cs
index e4d33bc24..7f2dcfe9c 100644
--- a/src/DslPackage/TextTemplates/EditingOnly/EFCore2ModelGenerator.cs
+++ b/src/DslPackage/TextTemplates/EditingOnly/EFCore2ModelGenerator.cs
@@ -3,8 +3,8 @@ namespace Sawczyn.EFDesigner.EFModel.EditingOnly
public partial class GeneratedTextTransformation
{
#region Template
- // EFDesigner v3.0.8.0
- // Copyright (c) 2017-2021 Michael Sawczyn
+ // EFDesigner v4.1.2.0
+ // Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
public class EFCore2ModelGenerator : EFCoreModelGenerator
@@ -15,3 +15,5 @@ public class EFCore2ModelGenerator : EFCoreModelGenerator
#endregion Template
}
}
+
+
diff --git a/src/DslPackage/TextTemplates/EditingOnly/EFCore3ModelGenerator.cs b/src/DslPackage/TextTemplates/EditingOnly/EFCore3ModelGenerator.cs
index 40cd3ea9a..a32ace3c1 100644
--- a/src/DslPackage/TextTemplates/EditingOnly/EFCore3ModelGenerator.cs
+++ b/src/DslPackage/TextTemplates/EditingOnly/EFCore3ModelGenerator.cs
@@ -6,15 +6,15 @@ public partial class GeneratedTextTransformation
{
#region Template
- // EFDesigner v3.0.8.0
- // Copyright (c) 2017-2021 Michael Sawczyn
+ // EFDesigner v4.1.2.0
+ // Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
public class EFCore3ModelGenerator : EFCore2ModelGenerator
{
public EFCore3ModelGenerator(GeneratedTextTransformation host) : base(host) { }
- protected override void WriteTargetDeleteBehavior(UnidirectionalAssociation association, List segments)
+ protected override void WriteTargetDeleteBehavior(Association association, List segments)
{
if (!association.Source.IsDependentType
&& !association.Target.IsDependentType
@@ -68,3 +68,5 @@ protected override void WriteSourceDeleteBehavior(BidirectionalAssociation assoc
#endregion Template
}
}
+
+
diff --git a/src/DslPackage/TextTemplates/EditingOnly/EFCore5ModelGenerator.cs b/src/DslPackage/TextTemplates/EditingOnly/EFCore5ModelGenerator.cs
index 4da7c86d4..71ba42a5d 100644
--- a/src/DslPackage/TextTemplates/EditingOnly/EFCore5ModelGenerator.cs
+++ b/src/DslPackage/TextTemplates/EditingOnly/EFCore5ModelGenerator.cs
@@ -1,32 +1,137 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Text;
+
+using Newtonsoft.Json;
+
+using Sawczyn.EFDesigner.EFModel.Annotations;
+
// ReSharper disable RedundantNameQualifier
namespace Sawczyn.EFDesigner.EFModel.EditingOnly
{
+ [UsedImplicitly]
public partial class GeneratedTextTransformation
{
#region Template
- // EFDesigner v3.0.8.0
- // Copyright (c) 2017-2021 Michael Sawczyn
+
+ // EFDesigner v4.1.2.0
+ // Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
public class EFCore5ModelGenerator : EFCore3ModelGenerator
{
public EFCore5ModelGenerator(GeneratedTextTransformation host) : base(host) { }
+ protected override void ConfigureModelClasses(List segments, ModelClass[] classesWithTables, List foreignKeyColumns, List visited)
+ {
+ foreach (ModelClass modelClass in modelRoot.Classes.Where(x => !x.IsAssociationClass).OrderBy(x => x.Name))
+ ConfigureModelClass(segments, classesWithTables, foreignKeyColumns, visited, modelClass);
+ }
+
+ protected override void ConfigureModelClass(List segments, ModelClass[] classesWithTables, List foreignKeyColumns, List visited, ModelClass modelClass)
+ {
+ segments.Clear();
+ foreignKeyColumns.Clear();
+ NL();
+
+ if (modelClass.IsDependentType)
+ {
+ segments.Add($"modelBuilder.Owned<{modelClass.FullName}>()");
+ Output(segments);
+
+ return;
+ }
+
+ segments.Add($"modelBuilder.Entity<{modelClass.FullName}>()");
+
+ ConfigureTransientProperties(segments, modelClass);
+
+ //if (modelRoot.InheritanceStrategy == CodeStrategy.TablePerConcreteType && modelClass.Superclass != null)
+ // segments.Add("Map(x => x.MapInheritedProperties())");
+
+ if (classesWithTables.Contains(modelClass))
+ {
+ if (modelClass.IsQueryType)
+ {
+ Output($"// There is no storage defined for {modelClass.Name} because its IsQueryType value is");
+ Output($"// set to 'true'. Please provide the {modelRoot.FullName}.Get{modelClass.Name}SqlQuery() method in the partial class.");
+ Output("// ");
+ Output($"// private string Get{modelClass.Name}SqlQuery()");
+ Output("// {");
+ Output($"// return the defining SQL query that pulls all the properties for {modelClass.FullName}");
+ Output("// }");
+
+ segments.Add($"ToSqlQuery(Get{modelClass.Name}SqlQuery())");
+ }
+ else
+ ConfigureTable(segments, modelClass);
+ }
+
+ if (segments.Count > 1 || modelClass.IsDependentType)
+ Output(segments);
+
+ // attribute level
+ ConfigureModelAttributes(segments, modelClass);
+
+ bool hasDefinedConcurrencyToken = modelClass.AllAttributes.Any(x => x.IsConcurrencyToken);
+
+ if (!hasDefinedConcurrencyToken && modelClass.EffectiveConcurrency == ConcurrencyOverride.Optimistic)
+ Output($@"modelBuilder.Entity<{modelClass.FullName}>().Property(""Timestamp"").IsConcurrencyToken();");
+
+ // Navigation endpoints are distingished as Source and Target. They are also distinguished as Principal
+ // and Dependent. So how do these map to each other? Short answer: they don't - they're orthogonal concepts.
+ // Source and Target are accidents of where the user started drawing the association, and help define where the
+ // properties are in unidirectional associations. Principal and Dependent define where the foreign keys go in
+ // the persistence mechanism.
+
+ // What matters to code generation is the Principal and Dependent classifications, so we focus on those.
+ // In the case of 1-1 or 0/1-0/1, it's situational, so the user has to tell us.
+ // In all other cases, we can tell by the cardinalities of the associations.
+
+ // navigation properties
+ List declaredShadowProperties = new List();
+
+ if (!modelClass.IsDependentType)
+ {
+ ConfigureUnidirectionalAssociations(modelClass, visited, foreignKeyColumns, declaredShadowProperties);
+ ConfigureBidirectionalAssociations(modelClass, visited, foreignKeyColumns, declaredShadowProperties);
+ }
+ }
+
protected override void ConfigureTable(List segments, ModelClass modelClass)
{
- string tableName = string.IsNullOrEmpty(modelClass.TableName) ? modelClass.Name : modelClass.TableName;
- string viewName = string.IsNullOrEmpty(modelClass.ViewName) ? modelClass.Name : modelClass.ViewName;
- string schema = string.IsNullOrEmpty(modelClass.DatabaseSchema) || modelClass.DatabaseSchema == modelClass.ModelRoot.DatabaseSchema ? string.Empty : $", \"{modelClass.DatabaseSchema}\"";
- string buildAction = modelClass.ExcludeFromMigrations ? ", t => t.ExcludeFromMigrations()" : string.Empty;
+ string tableName = string.IsNullOrEmpty(modelClass.TableName)
+ ? modelClass.Name
+ : modelClass.TableName;
+
+ string viewName = string.IsNullOrEmpty(modelClass.ViewName)
+ ? modelClass.Name
+ : modelClass.ViewName;
+
+ string schema = string.IsNullOrEmpty(modelClass.DatabaseSchema) || modelClass.DatabaseSchema == modelClass.ModelRoot.DatabaseSchema
+ ? string.Empty
+ : $", \"{modelClass.DatabaseSchema}\"";
+
+ List modifiers = new List();
+
+ if (modelClass.ExcludeFromMigrations)
+ modifiers.Add("t.ExcludeFromMigrations();");
- if (modelClass.IsDatabaseView)
- segments.Add($"ToView(\"{viewName}\"{schema}{buildAction})");
- else
- segments.Add($"ToTable(\"{tableName}\"{schema}{buildAction})");
+ if (modelClass.UseTemporalTables
+ && !modelClass.IsDatabaseView
+ && (!modelClass.Subclasses.Any() || modelClass.ModelRoot.InheritanceStrategy == CodeStrategy.TablePerHierarchy)
+ && modelClass.Superclass == null)
+ modifiers.Add("t.IsTemporal();");
+
+ string buildActions = modifiers.Any()
+ ? $", t => {{ {string.Join(" ", modifiers)} }}"
+ : string.Empty;
+
+ segments.Add(modelClass.IsDatabaseView
+ ? $"ToView(\"{viewName}\"{schema}{buildActions})"
+ : $"ToTable(\"{tableName}\"{schema}{buildActions})");
if (modelClass.Superclass != null)
segments.Add($"HasBaseType<{modelClass.Superclass.FullName}>()");
@@ -86,6 +191,14 @@ protected override List GatherModelAttributeSegments(ModelAttribute mode
&& modelAttribute.Type == "String")
segments.Add($"UseCollation(\"{modelAttribute.DatabaseCollation.Trim('"')}\")");
+ int index = segments.IndexOf("IsRequired()");
+
+ if (index >= 0)
+ {
+ segments.RemoveAt(index);
+ segments.Add("IsRequired()");
+ }
+
return segments;
}
@@ -155,7 +268,10 @@ protected override void WriteBidirectionalDependentAssociations(ModelClass sourc
visited.Add(association);
List segments = new List();
- string separator = sourceInstance.ModelRoot.ShadowKeyNamePattern == ShadowKeyPattern.TableColumn ? string.Empty : "_";
+
+ string separator = sourceInstance.ModelRoot.ShadowKeyNamePattern == ShadowKeyPattern.TableColumn
+ ? string.Empty
+ : "_";
switch (association.TargetMultiplicity) // realized by property on source
{
@@ -282,8 +398,7 @@ protected override void WriteBidirectionalNonDependentAssociations(ModelClass mo
visited.Add(association);
List segments = new List();
- bool sourceRequired = false;
- bool targetRequired = false;
+ bool required = false;
segments.Add($"modelBuilder.Entity<{modelClass.FullName}>()");
@@ -292,18 +407,12 @@ protected override void WriteBidirectionalNonDependentAssociations(ModelClass mo
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
{
segments.Add($"HasMany<{association.Target.FullName}>(p => p.{association.TargetPropertyName})");
+ required = association.SourceMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One;
break;
}
case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- {
- segments.Add($"HasOne<{association.Target.FullName}>(p => p.{association.TargetPropertyName})");
- targetRequired = true;
-
- break;
- }
-
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
{
segments.Add($"HasOne<{association.Target.FullName}>(p => p.{association.TargetPropertyName})");
@@ -315,67 +424,31 @@ protected override void WriteBidirectionalNonDependentAssociations(ModelClass mo
switch (association.SourceMultiplicity) // realized by property on target, but no property on target
{
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
+ segments.Add($"WithMany(p => p.{association.SourcePropertyName})");
+
+ if (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany)
{
- segments.Add($"WithMany(p => p.{association.SourcePropertyName})");
+ ModelClass associationClass = modelClass.Store.ElementDirectory.AllElements.OfType().FirstOrDefault(m => m.DescribedAssociationElementId == association.Id);
- if (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany)
+ if (associationClass == null)
+ segments.AddRange(WriteStandardBidirectionalAssociation(association, foreignKeyColumns, required));
+ else
{
- string tableMap = string.IsNullOrEmpty(association.JoinTableName)
- ? $"{association.Target.Name}_{association.SourcePropertyName}_x_{association.Source.Name}_{association.TargetPropertyName}"
- : association.JoinTableName;
-
- segments.Add($"UsingEntity(x => x.ToTable(\"{tableMap.Trim('"')}\"))");
+ OutputNoTerminator(segments);
+ WriteBidirectionalAssociationWithAssociationClass(modelClass, associationClass, association);
}
-
- break;
}
- case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- {
- segments.Add($"WithOne(p => p.{association.SourcePropertyName})");
- sourceRequired = true;
-
- break;
- }
+ break;
+ case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
segments.Add($"WithOne(p => p.{association.SourcePropertyName})");
break;
}
- string foreignKeySegment = CreateForeignKeySegment(association, foreignKeyColumns);
-
- if (!string.IsNullOrEmpty(foreignKeySegment))
- segments.Add(foreignKeySegment);
-
- if (association.Dependent == association.Target)
- {
- if (association.SourceDeleteAction == DeleteAction.None)
- segments.Add("OnDelete(DeleteBehavior.NoAction)");
- else if (association.SourceDeleteAction == DeleteAction.Cascade)
- segments.Add("OnDelete(DeleteBehavior.Cascade)");
-
- if (targetRequired)
- segments.Add("IsRequired()");
- }
- else if (association.Dependent == association.Source)
- {
- if (association.TargetDeleteAction == DeleteAction.None)
- segments.Add("OnDelete(DeleteBehavior.NoAction)");
- else if (association.TargetDeleteAction == DeleteAction.Cascade)
- segments.Add("OnDelete(DeleteBehavior.Cascade)");
-
- if (sourceRequired)
- segments.Add("IsRequired()");
- }
-
- Output(segments);
-
- if (association.Principal == association.Target && targetRequired)
- Output($"modelBuilder.Entity<{association.Source.FullName}>().Navigation(e => e.{association.TargetPropertyName}).IsRequired();");
- else if (association.Principal == association.Source && sourceRequired)
- Output($"modelBuilder.Entity<{association.Target.FullName}>().Navigation(e => e.{association.SourcePropertyName}).IsRequired();");
+ if (segments.Any()) Output(segments);
if (association.TargetAutoInclude)
Output($"modelBuilder.Entity<{association.Source.FullName}>().Navigation(e => e.{association.TargetPropertyName}).AutoInclude();");
@@ -385,19 +458,11 @@ protected override void WriteBidirectionalNonDependentAssociations(ModelClass mo
if (!association.TargetAutoProperty)
{
segments.Add($"modelBuilder.Entity<{association.Source.FullName}>().Navigation(e => e.{association.TargetPropertyName})");
+ segments.Add($"HasField(\"{association.TargetBackingFieldName}\")");
- if (association.Source == association.Principal)
- {
- segments.Add($"HasField(\"{association.TargetBackingFieldName}\")");
- segments.Add($"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode});");
- }
- else if (association.Target == association.Principal)
- {
- segments.Add($"HasField(\"{association.TargetBackingFieldName}\")");
- segments.Add($"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode});");
- }
- else
- segments.Add($"HasField(\"{association.TargetBackingFieldName}\");");
+ segments.Add(modelClass.ModelRoot.IsEFCore6Plus
+ ? $"UsePropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode})"
+ : $"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode})");
Output(segments);
}
@@ -405,26 +470,140 @@ protected override void WriteBidirectionalNonDependentAssociations(ModelClass mo
if (!association.SourceAutoProperty)
{
segments.Add($"modelBuilder.Entity<{association.Target.FullName}>().Navigation(e => e.{association.SourcePropertyName})");
+ segments.Add($"HasField(\"{association.SourceBackingFieldName}\")");
- if (association.Target == association.Principal)
- {
- segments.Add($"HasField(\"{association.SourceBackingFieldName}\")");
- segments.Add($"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.SourcePropertyAccessMode});");
- }
- else if (association.Source == association.Principal)
- {
- segments.Add($"HasField(\"{association.SourceBackingFieldName}\")");
- segments.Add($"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.SourcePropertyAccessMode});");
- }
- else
- segments.Add($"HasField(\"{association.SourceBackingFieldName}\");");
+ segments.Add(modelClass.ModelRoot.IsEFCore6Plus
+ ? $"UsePropertyAccessMode(PropertyAccessMode.{association.SourcePropertyAccessMode})"
+ : $"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.SourcePropertyAccessMode})");
Output(segments);
}
-
}
}
+ private IEnumerable WriteStandardBidirectionalAssociation(BidirectionalAssociation association, List foreignKeyColumns, bool required)
+ {
+ List segments = new List();
+
+ string tableMap = string.IsNullOrEmpty(association.JoinTableName)
+ ? $"{association.Target.Name}_{association.SourcePropertyName}_x_{association.Source.Name}_{association.TargetPropertyName}"
+ : association.JoinTableName;
+
+ segments.Add($"UsingEntity(x => x.ToTable(\"{tableMap}\"))");
+
+ string foreignKeySegment = CreateForeignKeySegment(association, foreignKeyColumns);
+
+ if (!string.IsNullOrEmpty(foreignKeySegment))
+ segments.Add(foreignKeySegment);
+
+ WriteSourceDeleteBehavior(association, segments);
+ WriteTargetDeleteBehavior(association, segments);
+
+ if (required
+ && (association.SourceMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One
+ || association.TargetMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One))
+ segments.Add("IsRequired()");
+
+ return segments;
+ }
+
+ private void WriteBidirectionalAssociationWithAssociationClass(ModelClass modelClass, ModelClass associationClass, BidirectionalAssociation association)
+ {
+ string indent = associationClass.ModelRoot.UseTabs
+ ? "\t"
+ : " ";
+ BidirectionalAssociation associationToSource = (BidirectionalAssociation)associationClass.AllNavigationProperties().First(n => n.AssociationObject.Source == association.Source).AssociationObject;
+ BidirectionalAssociation associationToTarget = (BidirectionalAssociation)associationClass.AllNavigationProperties().First(n => n.AssociationObject.Source == association.Target).AssociationObject;
+
+ if (modelClass.ModelRoot.ChopMethodChains)
+ PushIndent(" ");
+ else
+ PushIndent(indent);
+
+ Output($".UsingEntity<{associationClass.FullName}>(");
+ PushIndent(indent);
+ Output("j => j");
+ PushIndent(indent);
+ Output($".HasOne(x => x.{associationToTarget.SourcePropertyName})");
+ Output($".WithMany(x => x.{associationToTarget.TargetPropertyName})");
+ Output($".HasForeignKey(x => x.{associationClass.Attributes.First(a => a.IsForeignKeyFor == associationToTarget.Id).Name}),");
+ PopIndent();
+ Output("j => j");
+ PushIndent(indent);
+ Output($".HasOne(x => x.{associationToSource.SourcePropertyName})");
+ Output($".WithMany(x => x.{associationToSource.TargetPropertyName})");
+ Output($".HasForeignKey(x => x.{associationClass.Attributes.First(a => a.IsForeignKeyFor == associationToSource.Id).Name}),");
+ PopIndent();
+ Output("j =>");
+ Output("{");
+
+ #region transient properties
+
+ foreach (ModelAttribute transient in associationClass.Attributes.Where(x => !x.Persistent))
+ Output($"j.Ignore(t => t.{transient.Name});");
+
+ #endregion
+
+ #region table definition
+
+ string tableName = string.IsNullOrEmpty(associationClass.TableName)
+ ? associationClass.Name
+ : associationClass.TableName;
+
+ string schema = string.IsNullOrEmpty(associationClass.DatabaseSchema) || associationClass.DatabaseSchema == associationClass.ModelRoot.DatabaseSchema
+ ? string.Empty
+ : $", \"{associationClass.DatabaseSchema}\"";
+
+ List modifiers = new List();
+
+ if (associationClass.UseTemporalTables)
+ modifiers.Add(" t.IsTemporal();");
+
+ string buildActions = modifiers.Any()
+ ? $", t => {{ {string.Join(" ", modifiers)} }}"
+ : string.Empty;
+
+ Output($"j.ToTable(\"{tableName}\"{schema}{buildActions});");
+
+ List identityAttributes = associationClass.IdentityAttributes.ToList();
+
+ if (identityAttributes.Count == 1)
+ Output($"j.HasKey(t => t.{identityAttributes[0].Name});");
+ else if (identityAttributes.Count > 1)
+ Output($"j.HasKey(t => new {{ t.{string.Join(", t.", identityAttributes.Select(ia => ia.Name))} }});");
+
+ #endregion
+
+#region model attributes
+
+ foreach (ModelAttribute modelAttribute in associationClass.Attributes.Where(x => x.Persistent && !x.IsIdentity))
+ {
+ List buffer = new List();
+ buffer.AddRange(GatherModelAttributeSegments(modelAttribute));
+
+ if (buffer.Any())
+ Output($"j.Property(t => t.{modelAttribute.Name}).{string.Join(".", buffer)};");
+
+ if (modelAttribute.Indexed)
+ {
+ buffer.Clear();
+ buffer.Add($"HasIndex(t => t.{modelAttribute.Name})");
+
+ if (modelAttribute.IndexedUnique)
+ buffer.Add("IsUnique()");
+
+ Output($"j.{string.Join(".", buffer)};");
+ }
+ }
+
+#endregion
+
+ PopIndent();
+ Output("});");
+ PopIndent();
+ PopIndent();
+ }
+
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
protected override void ConfigureUnidirectionalAssociations(ModelClass modelClass
, List visited
@@ -448,7 +627,10 @@ protected override void WriteUnidirectionalDependentAssociations(ModelClass sour
visited.Add(association);
List segments = new List();
- string separator = sourceInstance.ModelRoot.ShadowKeyNamePattern == ShadowKeyPattern.TableColumn ? string.Empty : "_";
+
+ string separator = sourceInstance.ModelRoot.ShadowKeyNamePattern == ShadowKeyPattern.TableColumn
+ ? string.Empty
+ : "_";
switch (association.TargetMultiplicity) // realized by property on source
{
@@ -538,8 +720,7 @@ protected override void WriteUnidirectionalNonDependentAssociations(ModelClass m
visited.Add(association);
List segments = new List();
- bool sourceRequired = false;
- bool targetRequired = false;
+ bool required = false;
segments.Add($"modelBuilder.Entity<{modelClass.FullName}>()");
@@ -547,15 +728,11 @@ protected override void WriteUnidirectionalNonDependentAssociations(ModelClass m
{
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
segments.Add($"HasMany<{association.Target.FullName}>(p => p.{association.TargetPropertyName})");
+ required = (association.SourceMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One);
break;
case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- segments.Add($"HasOne<{association.Target.FullName}>(p => p.{association.TargetPropertyName})");
- targetRequired = true;
-
- break;
-
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
segments.Add($"HasOne<{association.Target.FullName}>(p => p.{association.TargetPropertyName})");
@@ -566,6 +743,7 @@ protected override void WriteUnidirectionalNonDependentAssociations(ModelClass m
{
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
segments.Add("WithMany()");
+ required = (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.One);
if (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany)
{
@@ -579,11 +757,6 @@ protected override void WriteUnidirectionalNonDependentAssociations(ModelClass m
break;
case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- segments.Add("WithOne()");
- sourceRequired = true;
-
- break;
-
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
segments.Add("WithOne()");
@@ -601,9 +774,6 @@ protected override void WriteUnidirectionalNonDependentAssociations(ModelClass m
segments.Add("OnDelete(DeleteBehavior.NoAction)");
else if (association.SourceDeleteAction == DeleteAction.Cascade)
segments.Add("OnDelete(DeleteBehavior.Cascade)");
-
- if (targetRequired)
- segments.Add("IsRequired()");
}
else if (association.Dependent == association.Source)
{
@@ -611,15 +781,12 @@ protected override void WriteUnidirectionalNonDependentAssociations(ModelClass m
segments.Add("OnDelete(DeleteBehavior.NoAction)");
else if (association.TargetDeleteAction == DeleteAction.Cascade)
segments.Add("OnDelete(DeleteBehavior.Cascade)");
-
- if (sourceRequired)
- segments.Add("IsRequired()");
}
- Output(segments);
+ if (required)
+ segments.Add("IsRequired()");
- if (association.Principal == association.Target && targetRequired)
- Output($"modelBuilder.Entity<{association.Source.FullName}>().Navigation(e => e.{association.TargetPropertyName}).IsRequired();");
+ Output(segments);
if (association.TargetAutoInclude)
Output($"modelBuilder.Entity<{association.Source.FullName}>().Navigation(e => e.{association.TargetPropertyName}).AutoInclude();");
@@ -628,18 +795,9 @@ protected override void WriteUnidirectionalNonDependentAssociations(ModelClass m
{
segments.Add($"modelBuilder.Entity<{association.Source.FullName}>().Navigation(e => e.{association.TargetPropertyName})");
- if (association.Source == association.Principal)
- {
- segments.Add($"HasField(\"{association.TargetBackingFieldName}\")");
- segments.Add($"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode});");
- }
- else if (association.Target == association.Principal)
- {
- segments.Add($"HasField(\"{association.TargetBackingFieldName}\")");
- segments.Add($"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode});");
- }
- else
- segments.Add($"HasField(\"{association.TargetBackingFieldName}\");");
+ segments.Add(modelClass.ModelRoot.IsEFCore6Plus
+ ? $"UsePropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode})"
+ : $"Metadata.SetPropertyAccessMode(PropertyAccessMode.{association.TargetPropertyAccessMode})");
Output(segments);
}
@@ -649,3 +807,6 @@ protected override void WriteUnidirectionalNonDependentAssociations(ModelClass m
#endregion Template
}
}
+
+
+
diff --git a/src/DslPackage/TextTemplates/EditingOnly/EFCoreDesigner.cs b/src/DslPackage/TextTemplates/EditingOnly/EFCoreDesigner.cs
index fad413b23..5084cbd27 100644
--- a/src/DslPackage/TextTemplates/EditingOnly/EFCoreDesigner.cs
+++ b/src/DslPackage/TextTemplates/EditingOnly/EFCoreDesigner.cs
@@ -1,6 +1,6 @@
#region Template
-// EFDesigner v3.0.8.0
-// Copyright (c) 2017-2021 Michael Sawczyn
+// EFDesigner v4.1.2.0
+// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
// This file is only present to support transition between v2.x EFModel templates and v3+ EFModel templates
@@ -8,4 +8,3 @@
#endregion Template
-
diff --git a/src/DslPackage/TextTemplates/EditingOnly/EFCoreModelGenerator.cs b/src/DslPackage/TextTemplates/EditingOnly/EFCoreModelGenerator.cs
index 5f5b4d471..48a90ed82 100644
--- a/src/DslPackage/TextTemplates/EditingOnly/EFCoreModelGenerator.cs
+++ b/src/DslPackage/TextTemplates/EditingOnly/EFCoreModelGenerator.cs
@@ -11,8 +11,8 @@ namespace Sawczyn.EFDesigner.EFModel.EditingOnly
public partial class GeneratedTextTransformation
{
#region Template
- // EFDesigner v3.0.8.0
- // Copyright (c) 2017-2021 Michael Sawczyn
+ // EFDesigner v4.1.2.0
+ // Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
public abstract class EFCoreModelGenerator : EFModelGenerator
@@ -124,7 +124,7 @@ protected void WriteDbContextFactory()
Output("}");
Output("}");
NL();
-
+
Output("/// ");
Output("/// Defines a factory for creating derived DbContext instances.");
Output("/// ");
@@ -181,79 +181,87 @@ protected override List GetAdditionalUsingStatements()
return result;
}
- protected virtual void ConfigureModelClasses(List segments, ModelClass[] classesWithTables, List foreignKeyColumns, List visited)
+ protected virtual void ConfigureModelClass(List segments, ModelClass[] classesWithTables, List foreignKeyColumns, List visited, ModelClass modelClass)
{
- foreach (ModelClass modelClass in modelRoot.Classes.OrderBy(x => x.Name))
- {
- segments.Clear();
- foreignKeyColumns.Clear();
- NL();
+ segments.Clear();
+ foreignKeyColumns.Clear();
+ NL();
- if (modelClass.IsDependentType)
- {
- segments.Add($"modelBuilder.Owned<{modelClass.FullName}>()");
- Output(segments);
- continue;
- }
+ if (modelClass.IsDependentType)
+ {
+ segments.Add($"modelBuilder.Owned<{modelClass.FullName}>()");
+ Output(segments);
+ return;
+ }
- segments.Add($"modelBuilder.Entity<{modelClass.FullName}>()");
+ segments.Add($"modelBuilder.Entity<{modelClass.FullName}>()");
- foreach (ModelAttribute transient in modelClass.Attributes.Where(x => !x.Persistent))
- segments.Add($"Ignore(t => t.{transient.Name})");
+ ConfigureTransientProperties(segments, modelClass);
- //if (modelRoot.InheritanceStrategy == CodeStrategy.TablePerConcreteType && modelClass.Superclass != null)
- // segments.Add("Map(x => x.MapInheritedProperties())");
+ //if (modelRoot.InheritanceStrategy == CodeStrategy.TablePerConcreteType && modelClass.Superclass != null)
+ // segments.Add("Map(x => x.MapInheritedProperties())");
- if (classesWithTables.Contains(modelClass))
+ if (classesWithTables.Contains(modelClass))
+ {
+ if (modelClass.IsQueryType)
{
- if (modelClass.IsQueryType)
- {
- Output($"// There is no storage defined for {modelClass.Name} because its IsQueryType value is");
- Output($"// set to 'true'. Please provide the {modelRoot.FullName}.Get{modelClass.Name}SqlQuery() method in the partial class.");
- Output("// ");
- Output($"// private string Get{modelClass.Name}SqlQuery()");
- Output("// {");
- Output($"// return the defining SQL query that pulls all the properties for {modelClass.FullName}");
- Output("// }");
-
- segments.Add($"ToSqlQuery(Get{modelClass.Name}SqlQuery())");
- }
- else
- ConfigureTable(segments, modelClass);
+ Output($"// There is no storage defined for {modelClass.Name} because its IsQueryType value is");
+ Output($"// set to 'true'. Please provide the {modelRoot.FullName}.Get{modelClass.Name}SqlQuery() method in the partial class.");
+ Output("// ");
+ Output($"// private string Get{modelClass.Name}SqlQuery()");
+ Output("// {");
+ Output($"// return the defining SQL query that pulls all the properties for {modelClass.FullName}");
+ Output("// }");
+
+ segments.Add($"ToSqlQuery(Get{modelClass.Name}SqlQuery())");
}
+ else
+ ConfigureTable(segments, modelClass);
+ }
- if (segments.Count > 1 || modelClass.IsDependentType)
- Output(segments);
+ if (segments.Count > 1 || modelClass.IsDependentType)
+ Output(segments);
- // attribute level
- ConfigureModelAttributes(segments, modelClass);
+ // attribute level
+ ConfigureModelAttributes(segments, modelClass);
- bool hasDefinedConcurrencyToken = modelClass.AllAttributes.Any(x => x.IsConcurrencyToken);
+ bool hasDefinedConcurrencyToken = modelClass.AllAttributes.Any(x => x.IsConcurrencyToken);
- if (!hasDefinedConcurrencyToken && modelClass.EffectiveConcurrency == ConcurrencyOverride.Optimistic)
- Output($@"modelBuilder.Entity<{modelClass.FullName}>().Property(""Timestamp"").IsConcurrencyToken();");
+ if (!hasDefinedConcurrencyToken && modelClass.EffectiveConcurrency == ConcurrencyOverride.Optimistic)
+ Output($@"modelBuilder.Entity<{modelClass.FullName}>().Property(""Timestamp"").IsConcurrencyToken();");
- // Navigation endpoints are distingished as Source and Target. They are also distinguished as Principal
- // and Dependent. So how do these map to each other? Short answer: they don't - they're orthogonal concepts.
- // Source and Target are accidents of where the user started drawing the association, and help define where the
- // properties are in unidirectional associations. Principal and Dependent define where the foreign keys go in
- // the persistence mechanism.
+ // Navigation endpoints are distingished as Source and Target. They are also distinguished as Principal
+ // and Dependent. So how do these map to each other? Short answer: they don't - they're orthogonal concepts.
+ // Source and Target are accidents of where the user started drawing the association, and help define where the
+ // properties are in unidirectional associations. Principal and Dependent define where the foreign keys go in
+ // the persistence mechanism.
- // What matters to code generation is the Principal and Dependent classifications, so we focus on those.
- // In the case of 1-1 or 0/1-0/1, it's situational, so the user has to tell us.
- // In all other cases, we can tell by the cardinalities of the associations.
+ // What matters to code generation is the Principal and Dependent classifications, so we focus on those.
+ // In the case of 1-1 or 0/1-0/1, it's situational, so the user has to tell us.
+ // In all other cases, we can tell by the cardinalities of the associations.
- // navigation properties
- List declaredShadowProperties = new List();
+ // navigation properties
+ List declaredShadowProperties = new List();
- if (!modelClass.IsDependentType)
- {
- ConfigureUnidirectionalAssociations(modelClass, visited, foreignKeyColumns, declaredShadowProperties);
- ConfigureBidirectionalAssociations(modelClass, visited, foreignKeyColumns, declaredShadowProperties);
- }
+ if (!modelClass.IsDependentType)
+ {
+ ConfigureUnidirectionalAssociations(modelClass, visited, foreignKeyColumns, declaredShadowProperties);
+ ConfigureBidirectionalAssociations(modelClass, visited, foreignKeyColumns, declaredShadowProperties);
}
}
+ protected virtual void ConfigureModelClasses(List segments, ModelClass[] classesWithTables, List foreignKeyColumns, List visited)
+ {
+ foreach (ModelClass modelClass in modelRoot.Classes.OrderBy(x => x.Name))
+ ConfigureModelClass(segments, classesWithTables, foreignKeyColumns, visited, modelClass);
+ }
+
+ protected static void ConfigureTransientProperties(List segments, ModelClass modelClass)
+ {
+ foreach (ModelAttribute transient in modelClass.Attributes.Where(x => !x.Persistent))
+ segments.Add($"Ignore(t => t.{transient.Name})");
+ }
+
protected virtual void ConfigureTable(List segments, ModelClass modelClass)
{
string tableName = string.IsNullOrEmpty(modelClass.TableName) ? modelClass.Name : modelClass.TableName;
@@ -562,106 +570,106 @@ protected virtual void WriteBidirectionalDependentAssociations(ModelClass source
switch (association.TargetMultiplicity) // realized by property on source
{
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
- {
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add($"ToTable(\"{(string.IsNullOrEmpty(association.Target.TableName) ? association.Target.Name : association.Target.TableName)}\")");
- Output(segments);
+ {
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add($"ToTable(\"{(string.IsNullOrEmpty(association.Target.TableName) ? association.Target.Name : association.Target.TableName)}\")");
+ Output(segments);
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add($"WithOwner(\"{association.SourcePropertyName}\")");
- segments.Add($"HasForeignKey(\"{association.SourcePropertyName}{separator}Id\")");
- Output(segments);
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add($"WithOwner(\"{association.SourcePropertyName}\")");
+ segments.Add($"HasForeignKey(\"{association.SourcePropertyName}{separator}Id\")");
+ Output(segments);
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add($"Property<{modelRoot.DefaultIdentityType}>(\"Id\")");
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add($"Property<{modelRoot.DefaultIdentityType}>(\"Id\")");
- Output(segments);
+ Output(segments);
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add("HasKey(\"Id\")");
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add("HasKey(\"Id\")");
- Output(segments);
+ Output(segments);
- WriteBidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsMany(p => p.{association.TargetPropertyName})", visited);
+ WriteBidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsMany(p => p.{association.TargetPropertyName})", visited);
- break;
- }
+ break;
+ }
case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- {
- segments.Add(baseSegment);
- segments.Add($"OwnsOne(p => p.{association.TargetPropertyName})");
- segments.Add($"WithOwner(p => p.{association.SourcePropertyName})");
- Output(segments);
-
- if (!string.IsNullOrEmpty(association.Target.TableName))
{
segments.Add(baseSegment);
segments.Add($"OwnsOne(p => p.{association.TargetPropertyName})");
- segments.Add($"ToTable(\"{association.Target.TableName}\")");
+ segments.Add($"WithOwner(p => p.{association.SourcePropertyName})");
Output(segments);
- }
- foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
- {
- segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
+ if (!string.IsNullOrEmpty(association.Target.TableName))
+ {
+ segments.Add(baseSegment);
+ segments.Add($"OwnsOne(p => p.{association.TargetPropertyName})");
+ segments.Add($"ToTable(\"{association.Target.TableName}\")");
+ Output(segments);
+ }
- if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
- segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
+ foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
+ {
+ segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
- if (modelAttribute.Required)
- segments.Add("IsRequired()");
+ if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
+ segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
- if (segments.Count > 1)
- Output(segments);
+ if (modelAttribute.Required)
+ segments.Add("IsRequired()");
- segments.Clear();
- }
+ if (segments.Count > 1)
+ Output(segments);
- WriteBidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
+ segments.Clear();
+ }
- break;
- }
+ WriteBidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
- case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
- {
- segments.Add(baseSegment);
- segments.Add($"OwnsOne(p => p.{association.TargetPropertyName})");
- segments.Add($"WithOwner(p => p.{association.SourcePropertyName})");
- Output(segments);
+ break;
+ }
- if (!string.IsNullOrEmpty(association.Target.TableName))
+ case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
{
segments.Add(baseSegment);
segments.Add($"OwnsOne(p => p.{association.TargetPropertyName})");
- segments.Add($"ToTable(\"{association.Target.TableName}\")");
+ segments.Add($"WithOwner(p => p.{association.SourcePropertyName})");
Output(segments);
- }
- foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
- {
- segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
+ if (!string.IsNullOrEmpty(association.Target.TableName))
+ {
+ segments.Add(baseSegment);
+ segments.Add($"OwnsOne(p => p.{association.TargetPropertyName})");
+ segments.Add($"ToTable(\"{association.Target.TableName}\")");
+ Output(segments);
+ }
- if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
- segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
+ foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
+ {
+ segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
- if (modelAttribute.Required)
- segments.Add("IsRequired()");
+ if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
+ segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
- if (segments.Count > 1)
- Output(segments);
+ if (modelAttribute.Required)
+ segments.Add("IsRequired()");
- segments.Clear();
- }
+ if (segments.Count > 1)
+ Output(segments);
- WriteBidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
+ segments.Clear();
+ }
- break;
- }
+ WriteBidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
+
+ break;
+ }
}
}
}
@@ -709,12 +717,12 @@ protected virtual void WriteBidirectionalNonDependentAssociations(ModelClass mod
if (association.TargetMultiplicity == Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany)
{
- string tableMap = string.IsNullOrEmpty(association.JoinTableName)
- ? $"{association.Target.Name}_{association.SourcePropertyName}_x_{association.Source.Name}_{association.TargetPropertyName}"
- : association.JoinTableName;
+ string tableMap = string.IsNullOrEmpty(association.JoinTableName)
+ ? $"{association.Target.Name}_{association.SourcePropertyName}_x_{association.Source.Name}_{association.TargetPropertyName}"
+ : association.JoinTableName;
- segments.Add($"UsingEntity(x => x.ToTable(\"{tableMap}\"))");
- }
+ segments.Add($"UsingEntity(x => x.ToTable(\"{tableMap}\"))");
+ }
break;
@@ -730,23 +738,23 @@ protected virtual void WriteBidirectionalNonDependentAssociations(ModelClass mod
break;
}
- string foreignKeySegment = CreateForeignKeySegment(association, foreignKeyColumns);
+ string foreignKeySegment = CreateForeignKeySegment(association, foreignKeyColumns);
- if (!string.IsNullOrEmpty(foreignKeySegment))
- segments.Add(foreignKeySegment);
+ if (!string.IsNullOrEmpty(foreignKeySegment))
+ segments.Add(foreignKeySegment);
- WriteSourceDeleteBehavior(association, segments);
+ WriteSourceDeleteBehavior(association, segments);
- if (required
- && (association.SourceMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One
- || association.TargetMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One))
- segments.Add("IsRequired()");
+ if (required
+ && (association.SourceMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One
+ || association.TargetMultiplicity != Sawczyn.EFDesigner.EFModel.Multiplicity.One))
+ segments.Add("IsRequired()");
Output(segments);
}
}
- protected virtual void WriteTargetDeleteBehavior(UnidirectionalAssociation association, List segments)
+ protected virtual void WriteTargetDeleteBehavior(Association association, List segments)
{
if (!association.Source.IsDependentType
&& !association.Target.IsDependentType
@@ -824,69 +832,69 @@ protected virtual void WriteUnidirectionalDependentAssociations(ModelClass sourc
switch (association.TargetMultiplicity) // realized by property on source
{
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroMany:
- {
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add($"WithOwner(\"{association.Source.Name}_{association.TargetPropertyName}\")");
- segments.Add($"HasForeignKey(\"{association.Source.Name}_{association.TargetPropertyName}{separator}Id\")");
- Output(segments);
+ {
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add($"WithOwner(\"{association.Source.Name}_{association.TargetPropertyName}\")");
+ segments.Add($"HasForeignKey(\"{association.Source.Name}_{association.TargetPropertyName}{separator}Id\")");
+ Output(segments);
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add($"Property<{modelRoot.DefaultIdentityType}>(\"Id\")");
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add($"Property<{modelRoot.DefaultIdentityType}>(\"Id\")");
- Output(segments);
+ Output(segments);
- segments.Add(baseSegment);
- segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
- segments.Add("HasKey(\"Id\")");
+ segments.Add(baseSegment);
+ segments.Add($"OwnsMany(p => p.{association.TargetPropertyName})");
+ segments.Add("HasKey(\"Id\")");
- Output(segments);
+ Output(segments);
- WriteUnidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsMany(p => p.{association.TargetPropertyName})", visited);
+ WriteUnidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsMany(p => p.{association.TargetPropertyName})", visited);
- break;
- }
+ break;
+ }
case Sawczyn.EFDesigner.EFModel.Multiplicity.One:
- {
- foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
{
- segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
+ foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
+ {
+ segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
- if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
- segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
+ if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
+ segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
- if (modelAttribute.Required)
- segments.Add("IsRequired()");
+ if (modelAttribute.Required)
+ segments.Add("IsRequired()");
- Output(segments);
- }
+ Output(segments);
+ }
- WriteUnidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
+ WriteUnidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
- break;
- }
+ break;
+ }
case Sawczyn.EFDesigner.EFModel.Multiplicity.ZeroOne:
- {
- foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
{
- segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
+ foreach (ModelAttribute modelAttribute in association.Target.AllAttributes)
+ {
+ segments.Add($"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName}).Property(p => p.{modelAttribute.Name})");
- if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
- segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
+ if (modelAttribute.ColumnName != modelAttribute.Name && !string.IsNullOrEmpty(modelAttribute.ColumnName))
+ segments.Add($"HasColumnName(\"{modelAttribute.ColumnName}\")");
- if (modelAttribute.Required)
- segments.Add("IsRequired()");
+ if (modelAttribute.Required)
+ segments.Add("IsRequired()");
- Output(segments);
- }
+ Output(segments);
+ }
- WriteUnidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
+ WriteUnidirectionalDependentAssociations(association.Target, $"{baseSegment}.OwnsOne(p => p.{association.TargetPropertyName})", visited);
- break;
- }
+ break;
+ }
}
}
}
@@ -1037,4 +1045,4 @@ protected virtual IEnumerable GetForeignKeys(Association association, Li
}
#endregion Template
}
-}
\ No newline at end of file
+}
diff --git a/src/DslPackage/TextTemplates/EditingOnly/EFDesigner.cs b/src/DslPackage/TextTemplates/EditingOnly/EFDesigner.cs
index ade75c7e6..dd3a9b2a1 100644
--- a/src/DslPackage/TextTemplates/EditingOnly/EFDesigner.cs
+++ b/src/DslPackage/TextTemplates/EditingOnly/EFDesigner.cs
@@ -25,8 +25,8 @@ public partial class GeneratedTextTransformation
#region Template
- // EFDesigner v3.0.8.0
- // Copyright (c) 2017-2021 Michael Sawczyn
+ // EFDesigner v4.1.2.0
+ // Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
public void GenerateEF6(Manager manager, ModelRoot modelRoot)
diff --git a/src/DslPackage/TextTemplates/EditingOnly/EFModelFileManager.cs b/src/DslPackage/TextTemplates/EditingOnly/EFModelFileManager.cs
index 683da638d..1ef60c857 100644
--- a/src/DslPackage/TextTemplates/EditingOnly/EFModelFileManager.cs
+++ b/src/DslPackage/TextTemplates/EditingOnly/EFModelFileManager.cs
@@ -16,8 +16,8 @@ public partial class GeneratedTextTransformation
{
#region Template
- // EFDesigner v3.0.8.0
- // Copyright (c) 2017-2021 Michael Sawczyn
+ // EFDesigner v4.1.2.0
+ // Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
public class Manager
@@ -201,7 +201,7 @@ public override string OutputPath
private void CheckoutFileIfRequired(string fileName)
{
- SourceControl sc = dte.SourceControl;
+ EnvDTE.SourceControl sc = dte.SourceControl;
if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName))
sc.CheckOutItem(fileName);
diff --git a/src/DslPackage/TextTemplates/EditingOnly/EFModelGenerator.cs b/src/DslPackage/TextTemplates/EditingOnly/EFModelGenerator.cs
index 2aae691f6..c7e5341b4 100644
--- a/src/DslPackage/TextTemplates/EditingOnly/EFModelGenerator.cs
+++ b/src/DslPackage/TextTemplates/EditingOnly/EFModelGenerator.cs
@@ -12,8 +12,8 @@ namespace Sawczyn.EFDesigner.EFModel.EditingOnly
public partial class GeneratedTextTransformation
{
#region Template
- // EFDesigner v3.0.8.0
- // Copyright (c) 2017-2021 Michael Sawczyn
+ // EFDesigner v4.1.2.0
+ // Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
protected void NL()
@@ -31,6 +31,16 @@ protected void Output(List segments)
segments.Clear();
}
+ protected void OutputNoTerminator(List segments)
+ {
+ if (ModelRoot.ChopMethodChains)
+ OutputChoppedNoTerminator(segments);
+ else
+ Output(string.Join(".", segments));
+
+ segments.Clear();
+ }
+
protected void Output(string text)
{
if (text == "}")
@@ -79,6 +89,34 @@ protected void OutputChopped(List segments)
segments.Clear();
}
+ protected void OutputChoppedNoTerminator(List segments)
+ {
+ string[] segmentArray = segments?.ToArray() ?? new string[0];
+
+ if (!segmentArray.Any())
+ return;
+
+ int indent = segmentArray[0].IndexOf('.');
+
+ if (indent == -1)
+ {
+ if (segmentArray.Length > 1)
+ {
+ segmentArray[0] = $"{segmentArray[0]}.{segmentArray[1]}";
+ indent = segmentArray[0].IndexOf('.');
+ segmentArray = segmentArray.Where((source, index) => index != 1).ToArray();
+ }
+ }
+
+ for (int index = 1; index < segmentArray.Length; ++index)
+ segmentArray[index] = $"{new string(' ', indent)}.{segmentArray[index]}";
+
+ foreach (string segment in segmentArray)
+ Output(segment);
+
+ segments.Clear();
+ }
+
public abstract class EFModelGenerator
{
protected static string[] xmlDocTags =
@@ -139,8 +177,11 @@ protected EFModelGenerator(GeneratedTextTransformation host)
// implementations delegated to the surrounding GeneratedTextTransformation for backward compatability
protected void NL() { host.NL(); }
protected void Output(List segments) { host.Output(segments); }
+ protected void OutputNoTerminator(List segments) { host.OutputNoTerminator(segments); }
protected void Output(string text) { host.Output(text); }
protected void Output(string template, params object[] items) { host.Output(template, items); }
+ protected void PushIndent(string indent) { host.PushIndent(indent); }
+ protected void PopIndent() { host.PopIndent(); }
protected void ClearIndent() { host.ClearIndent(); }
public static string[] NonNullableTypes
@@ -278,10 +319,10 @@ protected void GeneratePropertyAnnotations(ModelAttribute modelAttribute)
}
if (!string.IsNullOrWhiteSpace(modelAttribute.DisplayText))
- Output($"[Display(Name=\"{modelAttribute.DisplayText.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.DataAnnotations.Display(Name=\"{modelAttribute.DisplayText.Replace("\"", "\\\"")}\")]");
if (!string.IsNullOrWhiteSpace(modelAttribute.Summary))
- Output($"[System.ComponentModel.Description(\"{modelAttribute.Summary.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.Description(\"{modelAttribute.Summary.Trim('\r', '\n').Replace("\"", "\\\"")}\")]");
}
protected abstract List GetAdditionalUsingStatements();
@@ -362,7 +403,8 @@ protected string GetMigrationNamespace()
nsParts.Add("Migrations");
return string.Join(".", nsParts);
- } protected List GetRequiredParameterNames(ModelClass modelClass, bool publicOnly = false)
+ }
+ protected List GetRequiredParameterNames(ModelClass modelClass, bool publicOnly = false)
{
return GetRequiredParameters(modelClass, null, publicOnly).Select(p => p.Split(' ')[1]).ToList();
}
@@ -479,7 +521,7 @@ protected virtual void WriteClass(ModelClass modelClass)
Output($"[{modelClass.CustomAttributes.Trim('[', ']')}]");
if (!string.IsNullOrWhiteSpace(modelClass.Summary))
- Output($"[System.ComponentModel.Description(\"{modelClass.Summary.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.Description(\"{modelClass.Summary.Trim('\r', '\n').Replace("\"", "\\\"")}\")]");
Output(baseClass.Length > 0
? $"public {isAbstract}partial class {modelClass.Name}: {baseClass}"
@@ -504,7 +546,7 @@ protected string[] GenerateCommentBody(string comment)
if (!string.IsNullOrEmpty(comment))
{
int chunkSize = 80;
- string[] parts = comment.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.RemoveEmptyEntries);
+ string[] parts = comment.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string value in parts)
{
@@ -536,7 +578,7 @@ protected string[] GenerateCommentBody(string comment)
protected void WriteCommentBody(string comment)
{
foreach (string s in GenerateCommentBody(comment))
- Output($"/// {s}");
+ Output($"/// {s}");
}
protected void WriteConstructor(ModelClass modelClass)
@@ -674,7 +716,11 @@ protected void WriteConstructor(ModelClass modelClass)
else if (requiredAttribute.Type.StartsWith("Geo"))
Output($"if ({requiredAttribute.Name.ToLower()} == null) throw new ArgumentNullException(nameof({requiredAttribute.Name.ToLower()}));");
- Output($"this.{requiredAttribute.Name} = {requiredAttribute.Name.ToLower()};");
+ string lhs = requiredAttribute.AutoProperty || string.IsNullOrEmpty(requiredAttribute.BackingFieldName)
+ ? requiredAttribute.Name
+ : requiredAttribute.BackingFieldName;
+
+ Output($"this.{lhs} = {requiredAttribute.Name.ToLower()};");
NL();
}
@@ -692,9 +738,13 @@ protected void WriteConstructor(ModelClass modelClass)
if (modelAttribute.Type == "decimal")
initialValue += "m";
+ string lhs = modelAttribute.AutoProperty || string.IsNullOrEmpty(modelAttribute.BackingFieldName)
+ ? modelAttribute.Name
+ : modelAttribute.BackingFieldName;
+
Output(quote.Length > 0
- ? $"this.{modelAttribute.Name} = {quote}{FullyQualified(initialValue.Trim(quote[0]))}{quote};"
- : $"this.{modelAttribute.Name} = {quote}{FullyQualified(initialValue)}{quote};");
+ ? $"this.{lhs} = {quote}{FullyQualified(initialValue.Trim(quote[0]))}{quote};"
+ : $"this.{lhs} = {quote}{FullyQualified(initialValue)}{quote};");
}
// all required navigation properties that aren't a 1..1 relationship
@@ -706,17 +756,21 @@ protected void WriteConstructor(ModelClass modelClass)
string parameterName = requiredNavigationProperty.PropertyName.ToLower();
Output($"if ({parameterName} == null) throw new ArgumentNullException(nameof({parameterName}));");
+ string targetObjectName = requiredNavigationProperty.IsAutoProperty
+ ? requiredNavigationProperty.PropertyName
+ : requiredNavigationProperty.BackingFieldName;
+
if (!requiredNavigationProperty.ConstructorParameterOnly)
{
Output(requiredNavigationProperty.IsCollection
- ? $"{requiredNavigationProperty.PropertyName}.Add({parameterName});"
- : $"this.{requiredNavigationProperty.PropertyName} = {parameterName};");
+ ? $"this.{targetObjectName}.Add({parameterName});"
+ : $"this.{targetObjectName} = {parameterName};");
}
if (!string.IsNullOrEmpty(otherSide.PropertyName))
{
- Output(otherSide.IsCollection
- ? $"{parameterName}.{otherSide.PropertyName}.Add(this);"
+ Output(otherSide.IsCollection
+ ? $"{parameterName}.{otherSide.PropertyName}.Add(this);"
: $"{parameterName}.{otherSide.PropertyName} = this;");
}
@@ -841,9 +895,13 @@ protected void WriteDefaultConstructorBody(ModelClass modelClass)
if (modelAttribute.Type == "decimal")
initialValue += "m";
+ string lhs = modelAttribute.AutoProperty || string.IsNullOrEmpty(modelAttribute.BackingFieldName)
+ ? modelAttribute.Name
+ : modelAttribute.BackingFieldName;
+
Output(quote.Length == 1
- ? $"{modelAttribute.Name} = {quote}{FullyQualified(initialValue.Trim(quote[0]))}{quote};"
- : $"{modelAttribute.Name} = {quote}{FullyQualified(initialValue)}{quote};");
+ ? $"{lhs} = {quote}{FullyQualified(initialValue.Trim(quote[0]))}{quote};"
+ : $"{lhs} = {quote}{FullyQualified(initialValue)}{quote};");
++lineCount;
}
@@ -884,7 +942,7 @@ protected void WriteEnum(ModelEnum modelEnum)
Output($"[{modelEnum.CustomAttributes.Trim('[', ']')}]");
if (!string.IsNullOrWhiteSpace(modelEnum.Summary))
- Output($"[System.ComponentModel.Description(\"{modelEnum.Summary.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.Description(\"{modelEnum.Summary.Trim('\r', '\n').Replace("\"", "\\\"")}\")]");
Output($"public enum {modelEnum.Name} : {modelEnum.ValueType}");
Output("{");
@@ -911,10 +969,10 @@ protected void WriteEnum(ModelEnum modelEnum)
Output($"[{values[index].CustomAttributes.Trim('[', ']')}]");
if (!string.IsNullOrWhiteSpace(values[index].Summary))
- Output($"[System.ComponentModel.Description(\"{values[index].Summary.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.Description(\"{values[index].Summary.Trim('\r', '\n').Replace("\"", "\\\"")}\")]");
if (!string.IsNullOrWhiteSpace(values[index].DisplayText))
- Output($"[System.ComponentModel.DataAnnotations.Display(Name=\"{values[index].DisplayText.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.DataAnnotations.Display(Name=\"{values[index].DisplayText.Trim('\r', '\n').Replace("\"", "\\\"")}\")]");
Output(string.IsNullOrEmpty(values[index].Value)
? $"{values[index].Name}{(index < values.Length - 1 ? "," : string.Empty)}"
@@ -937,7 +995,7 @@ protected void WriteNavigationProperties(ModelClass modelClass)
Output(" *************************************************************************/");
NL();
- foreach (NavigationProperty navigationProperty in modelClass.LocalNavigationProperties().Where(x => !x.ConstructorParameterOnly))
+ foreach (NavigationProperty navigationProperty in modelClass.LocalNavigationProperties().Where(x => !x.ConstructorParameterOnly).OrderBy(x => x.PropertyName))
{
string type = navigationProperty.IsCollection
? $"ICollection<{navigationProperty.ClassType.FullName}>"
@@ -1004,10 +1062,10 @@ protected void WriteNavigationProperties(ModelClass modelClass)
Output($"[{navigationProperty.CustomAttributes.Trim('[', ']')}]");
if (!string.IsNullOrWhiteSpace(navigationProperty.Summary))
- Output($"[Description(\"{navigationProperty.Summary.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.Description(\"{navigationProperty.Summary.Replace("\"", "\\\"")}\")]");
if (!string.IsNullOrWhiteSpace(navigationProperty.DisplayText))
- Output($"[Display(Name=\"{navigationProperty.DisplayText.Replace("\"", "\\\"")}\")]");
+ Output($"[System.ComponentModel.DataAnnotations.Display(Name=\"{navigationProperty.DisplayText.Replace("\"", "\\\"")}\")]");
if (navigationProperty.IsAutoProperty)
{
@@ -1042,7 +1100,7 @@ protected void WriteNavigationProperties(ModelClass modelClass)
Output("}");
Output("set");
Output("{");
- Output($"{type} oldValue = {navigationProperty.BackingFieldName};");
+ Output($"{type} oldValue = {navigationProperty.PropertyName};");
Output($"Set{navigationProperty.PropertyName}(oldValue, ref value);");
Output("if (oldValue != value)");
Output("{");
@@ -1069,7 +1127,7 @@ protected void WriteProperties(ModelClass modelClass)
List segments = new List();
- foreach (ModelAttribute modelAttribute in modelClass.Attributes)
+ foreach (ModelAttribute modelAttribute in modelClass.Attributes.OrderBy(x => x.Name))
{
segments.Clear();
@@ -1174,7 +1232,7 @@ protected void WriteProperties(ModelClass modelClass)
Output("}");
Output($"{setterVisibility}set");
Output("{");
- Output($"{modelAttribute.FQPrimitiveType}{nullable} oldValue = {modelAttribute.BackingFieldName};");
+ Output($"{modelAttribute.FQPrimitiveType}{nullable} oldValue = {modelAttribute.Name};");
Output($"Set{modelAttribute.Name}(oldValue, ref value);");
Output("if (oldValue != value)");
Output("{");
@@ -1197,7 +1255,7 @@ protected void WriteProperties(ModelClass modelClass)
Output("/// ");
Output("/// Concurrency token");
Output("/// ");
- Output("[Timestamp]");
+ Output("[System.ComponentModel.DataAnnotations.Timestamp]");
Output("public Byte[] Timestamp { get; set; }");
NL();
}
@@ -1206,3 +1264,4 @@ protected void WriteProperties(ModelClass modelClass)
#endregion Template
}
}
+
diff --git a/src/DslPackage/TextTemplates/EditingOnly/MultipleOutputHelper.cs b/src/DslPackage/TextTemplates/EditingOnly/MultipleOutputHelper.cs
index cfca03202..913940b0b 100644
--- a/src/DslPackage/TextTemplates/EditingOnly/MultipleOutputHelper.cs
+++ b/src/DslPackage/TextTemplates/EditingOnly/MultipleOutputHelper.cs
@@ -1,10 +1,8 @@
#region Template
-// EFDesigner v3.0.8.0
-// Copyright (c) 2017-2021 Michael Sawczyn
+// EFDesigner v4.1.2.0
+// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
// This file is only present to support transition between v2.x EFModel templates and v3+ EFModel templates
// It will be removed in a future version of the tool
#endregion Template
-
-
diff --git a/src/DslPackage/TextTemplates/EditingOnly/VSIntegration.cs b/src/DslPackage/TextTemplates/EditingOnly/VSIntegration.cs
index 2b14f56e7..dd986b9bf 100644
--- a/src/DslPackage/TextTemplates/EditingOnly/VSIntegration.cs
+++ b/src/DslPackage/TextTemplates/EditingOnly/VSIntegration.cs
@@ -14,8 +14,8 @@ public partial class GeneratedTextTransformation
{
#region Template
- // EFDesigner v3.0.8.0
- // Copyright (c) 2017-2021 Michael Sawczyn
+ // EFDesigner v4.1.2.0
+ // Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
// this bit is based on EntityFramework Reverse POCO Code First Generator
@@ -27,7 +27,7 @@ public partial class GeneratedTextTransformation
* Interactions with Visual Studio
*/
- public IEnumerable GetAllProjects()
+ public IEnumerable GetAllProjects()
{
foreach (Project project in GetSolution().Projects.OfType())
{
@@ -67,7 +67,7 @@ public Project GetCurrentProject()
throw new InvalidOperationException("Error in GetCurrentProject(). Unable to find project.");
}
- private ProjectItem GetDirectoryItem(string target)
+ private EnvDTE.ProjectItem GetDirectoryItem(string target)
{
DTE dte = GetDTE();
Array projects = dte?.ActiveSolutionProjects as Array;
@@ -80,7 +80,7 @@ private ProjectItem GetDirectoryItem(string target)
Directory.CreateDirectory(Path.Combine(rootDirectory, target));
Queue paths = new Queue(target.Split('\\'));
- ProjectItems currentItemList = currentProject.ProjectItems;
+ EnvDTE.ProjectItems currentItemList = currentProject.ProjectItems;
bool found = false;
while (paths.Any())
@@ -117,7 +117,7 @@ private ProjectItem GetDirectoryItem(string target)
return targetProjectItem;
}
- public DTE GetDTE()
+ public EnvDTE.DTE GetDTE()
{
IServiceProvider serviceProvider = (IServiceProvider)Host;
@@ -153,7 +153,7 @@ private string GetProjectPath(Project project)
}
}
- public Solution GetSolution()
+ public EnvDTE.Solution GetSolution()
{
return GetDTE().Solution;
}
@@ -181,3 +181,5 @@ private IEnumerable RecurseSolutionFolder(Project project)
#endregion Template
}
}
+
+
diff --git a/src/DslPackage/TextTemplates/MultipleOutputHelper.ttinclude b/src/DslPackage/TextTemplates/MultipleOutputHelper.ttinclude
index 3a3a235e0..7a297cbdc 100644
--- a/src/DslPackage/TextTemplates/MultipleOutputHelper.ttinclude
+++ b/src/DslPackage/TextTemplates/MultipleOutputHelper.ttinclude
@@ -23,7 +23,7 @@
#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
-// EFDesigner v3.1.0.0
+// EFDesigner v4.1.2.0
// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
diff --git a/src/DslPackage/TextTemplates/VSIntegration.ttinclude b/src/DslPackage/TextTemplates/VSIntegration.ttinclude
index 5d5f51745..78e6fe15f 100644
--- a/src/DslPackage/TextTemplates/VSIntegration.ttinclude
+++ b/src/DslPackage/TextTemplates/VSIntegration.ttinclude
@@ -23,7 +23,7 @@
#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
- // EFDesigner v3.1.0.0
+ // EFDesigner v4.1.2.0
// Copyright (c) 2017-2022 Michael Sawczyn
// https://github.com/msawczyn/EFDesigner
@@ -36,7 +36,7 @@
* Interactions with Visual Studio
*/
- public IEnumerable GetAllProjects()
+ public IEnumerable GetAllProjects()
{
foreach (Project project in GetSolution().Projects.OfType())
{
@@ -76,7 +76,7 @@
throw new InvalidOperationException("Error in GetCurrentProject(). Unable to find project.");
}
- private ProjectItem GetDirectoryItem(string target)
+ private EnvDTE.ProjectItem GetDirectoryItem(string target)
{
DTE dte = GetDTE();
Array projects = dte?.ActiveSolutionProjects as Array;
@@ -89,7 +89,7 @@
Directory.CreateDirectory(Path.Combine(rootDirectory, target));
Queue paths = new Queue(target.Split('\\'));
- ProjectItems currentItemList = currentProject.ProjectItems;
+ EnvDTE.ProjectItems currentItemList = currentProject.ProjectItems;
bool found = false;
while (paths.Any())
@@ -126,7 +126,7 @@
return targetProjectItem;
}
- public DTE GetDTE()
+ public EnvDTE.DTE GetDTE()
{
IServiceProvider serviceProvider = (IServiceProvider)Host;
@@ -162,7 +162,7 @@
}
}
- public Solution GetSolution()
+ public EnvDTE.Solution GetSolution()
{
return GetDTE().Solution;
}
diff --git a/src/DslPackage/source.extension.vsixmanifest b/src/DslPackage/source.extension.vsixmanifest
index 88c97878e..3b294bc2e 100644
--- a/src/DslPackage/source.extension.vsixmanifest
+++ b/src/DslPackage/source.extension.vsixmanifest
@@ -1,7 +1,7 @@
-
+
Entity Framework Visual Editor
Entity Framework visual editor for EF6, EFCore and beyond.
Logo.ico
diff --git a/src/Testing/EFCoreV5/EFCore5Net5/EFModel1.efmodel b/src/Testing/EFCoreV5/EFCore5Net5/EFModel1.efmodel
index d03ef259a..4bbc927df 100644
--- a/src/Testing/EFCoreV5/EFCore5Net5/EFModel1.efmodel
+++ b/src/Testing/EFCoreV5/EFCore5Net5/EFModel1.efmodel
@@ -1,10 +1,10 @@
-
+
-
+
-
+
@@ -14,36 +14,65 @@
-
+
-
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Testing/EFCoreV5/EFCore5Net5/EFModel1.efmodel.diagramx b/src/Testing/EFCoreV5/EFCore5Net5/EFModel1.efmodel.diagramx
index a6604c26d..654a06f83 100644
--- a/src/Testing/EFCoreV5/EFCore5Net5/EFModel1.efmodel.diagramx
+++ b/src/Testing/EFCoreV5/EFCore5Net5/EFModel1.efmodel.diagramx
@@ -1,40 +1,43 @@
-
+
-
+
+
-
-
-
+
+
+
-
+
+
-
-
-
+
+
+
-
+
-
+
+
-
-
-
+
+
+
-
+
@@ -42,15 +45,16 @@
-
+
+
-
-
-
+
+
+
-
+
@@ -58,6 +62,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Testing/EFCoreV5/EFCore5Net5/Generated/AssocClass.generated.cs b/src/Testing/EFCoreV5/EFCore5Net5/Generated/AssocClass.generated.cs
new file mode 100644
index 000000000..2bbb4675e
--- /dev/null
+++ b/src/Testing/EFCoreV5/EFCore5Net5/Generated/AssocClass.generated.cs
@@ -0,0 +1,139 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated from a template.
+//
+// Manual changes to this file may cause unexpected behavior in your application.
+// Manual changes to this file will be overwritten if the code is regenerated.
+//
+// Produced by Entity Framework Visual Editor v4.1.2.0
+// Source: https://github.com/msawczyn/EFDesigner
+// Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner
+// Documentation: https://msawczyn.github.io/EFDesigner/
+// License (MIT): https://github.com/msawczyn/EFDesigner/blob/master/LICENSE
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Linq;
+using System.Runtime.CompilerServices;
+
+namespace Testing
+{
+ public partial class AssocClass
+ {
+ partial void Init();
+
+ ///
+ /// Default constructor. Protected due to required properties, but present because EF needs it.
+ ///
+ protected AssocClass()
+ {
+ Init();
+ }
+
+ ///
+ /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving.
+ ///
+ public static AssocClass CreateAssocClassUnsafe()
+ {
+ return new AssocClass();
+ }
+
+ ///
+ /// Public constructor with required data
+ ///
+ /// Unique identifier
+ /// Foreign key for EntityImplementation.Entity2_Entity3 <--> Entity3.EntityImplementations.
+ /// Foreign key for Entity2.EntityImplementations_Entity3 <--> Entity3.Entity2.
+ /// Association class for EntityImplementations
+ /// Association class for Entity2
+ public AssocClass(long id, long entity2id, long entityimplementationsid, global::Testing.EntityImplementation entityimplementations, global::Testing.Entity2 entity2)
+ {
+ this.Id = id;
+
+ this.Entity2Id = entity2id;
+
+ this.EntityImplementationsId = entityimplementationsid;
+
+ if (entityimplementations == null) throw new ArgumentNullException(nameof(entityimplementations));
+ this.EntityImplementations = entityimplementations;
+ entityimplementations.Entity2_Entity3.Add(this);
+
+ if (entity2 == null) throw new ArgumentNullException(nameof(entity2));
+ this.Entity2 = entity2;
+ entity2.EntityImplementations_Entity3.Add(this);
+
+ Init();
+ }
+
+ ///
+ /// Static create function (for use in LINQ queries, etc.)
+ ///
+ /// Unique identifier
+ /// Foreign key for EntityImplementation.Entity2_Entity3 <--> Entity3.EntityImplementations.
+ /// Foreign key for Entity2.EntityImplementations_Entity3 <--> Entity3.Entity2.
+ /// Association class for EntityImplementations
+ /// Association class for Entity2
+ public static AssocClass Create(long id, long entity2id, long entityimplementationsid, global::Testing.EntityImplementation entityimplementations, global::Testing.Entity2 entity2)
+ {
+ return new AssocClass(id, entity2id, entityimplementationsid, entityimplementations, entity2);
+ }
+
+ /*************************************************************************
+ * Properties
+ *************************************************************************/
+
+ ///
+ /// Identity, Indexed, Required
+ /// Foreign key for EntityImplementation.Entity2_Entity3 <--> Entity3.EntityImplementations.
+ ///
+ [Key]
+ [Required]
+ [System.ComponentModel.Description("Foreign key for EntityImplementation.Entity2_Entity3 <--> Entity3.EntityImplementations. ")]
+ public long Entity2Id { get; set; }
+
+ ///
+ /// Identity, Indexed, Required
+ /// Foreign key for Entity2.EntityImplementations_Entity3 <--> Entity3.Entity2.
+ ///
+ [Key]
+ [Required]
+ [System.ComponentModel.Description("Foreign key for Entity2.EntityImplementations_Entity3 <--> Entity3.Entity2. ")]
+ public long EntityImplementationsId { get; set; }
+
+ ///
+ /// Indexed, Required
+ /// Unique identifier
+ ///
+ [Required]
+ [System.ComponentModel.Description("Unique identifier")]
+ public long Id { get; set; }
+
+ /*************************************************************************
+ * Navigation properties
+ *************************************************************************/
+
+ ///
+ /// Required<br/>
+ /// Association class for Entity2
+ ///
+ [System.ComponentModel.Description("Association class for Entity2")]
+ [System.ComponentModel.DataAnnotations.Display(Name="Association object for Entity2")]
+ public virtual global::Testing.Entity2 Entity2 { get; set; }
+
+ ///
+ /// Required<br/>
+ /// Association class for EntityImplementations
+ ///
+ [System.ComponentModel.Description("Association class for EntityImplementations")]
+ [System.ComponentModel.DataAnnotations.Display(Name="Association object for EntityImplementations")]
+ public virtual global::Testing.EntityImplementation EntityImplementations { get; set; }
+
+ }
+}
+
diff --git a/src/Testing/EFCoreV5/EFCore5Net5/Generated/EFModel1.generated.cs b/src/Testing/EFCoreV5/EFCore5Net5/Generated/EFModel1.generated.cs
index 5d4c42aa0..e53e7a0b1 100644
--- a/src/Testing/EFCoreV5/EFCore5Net5/Generated/EFModel1.generated.cs
+++ b/src/Testing/EFCoreV5/EFCore5Net5/Generated/EFModel1.generated.cs
@@ -5,7 +5,7 @@
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
//
-// Produced by Entity Framework Visual Editor v3.0.4.7
+// Produced by Entity Framework Visual Editor v4.1.2.0
// Source: https://github.com/msawczyn/EFDesigner
// Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner
// Documentation: https://msawczyn.github.io/EFDesigner/
@@ -25,7 +25,9 @@ namespace Testing
public partial class EFModel1 : DbContext
{
#region DbSets
+ public virtual Microsoft.EntityFrameworkCore.DbSet AssocClasses { get; set; }
public virtual Microsoft.EntityFrameworkCore.DbSet Entity1 { get; set; }
+ public virtual Microsoft.EntityFrameworkCore.DbSet Entity2 { get; set; }
public virtual Microsoft.EntityFrameworkCore.DbSet EntityAbstract { get; set; }
public virtual Microsoft.EntityFrameworkCore.DbSet EntityImplementation { get; set; }
public virtual Microsoft.EntityFrameworkCore.DbSet EntityRelated { get; set; }
@@ -37,7 +39,14 @@ public partial class EFModel1 : DbContext
///
public static string ConnectionString { get; set; } = @"Data Source=.\sqlexpress;Initial Catalog=Test;Integrated Security=True";
- ///
+ ///
+ ///
+ /// Initializes a new instance of the class using the specified options.
+ /// The method will still be called to allow further
+ /// configuration of the options.
+ ///
+ ///
+ /// The options for this context.
public EFModel1(DbContextOptions options) : base(options)
{
}
@@ -55,7 +64,20 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
partial void OnModelCreatingImpl(ModelBuilder modelBuilder);
partial void OnModelCreatedImpl(ModelBuilder modelBuilder);
- ///
+ ///
+ /// Override this method to further configure the model that was discovered by convention from the entity types
+ /// exposed in properties on your derived context. The resulting model may be cached
+ /// and re-used for subsequent instances of your derived context.
+ ///
+ ///
+ /// If a model is explicitly set on the options for this context (via )
+ /// then this method will not be run.
+ ///
+ ///
+ /// The builder being used to construct the model for this context. Databases (and other extensions) typically
+ /// define extension methods on this object that allow you to configure aspects of the model that are specific
+ /// to a given database.
+ ///
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
@@ -71,11 +93,20 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.ValueGeneratedOnAdd()
.IsRequired();
modelBuilder.Entity()
- .HasOne(p => p.EntityImplementation)
- .WithOne(p => p.Entity1)
- .HasForeignKey("Entity1", "EntityImplementationId")
- .OnDelete(DeleteBehavior.Cascade);
- modelBuilder.Entity().Navigation(e => e.EntityImplementation).IsRequired();
+ .HasMany(p => p.EntityImplementations)
+ .WithMany(p => p.Entity1)
+ .UsingEntity(x => x.ToTable("EntityImplementation_Entity1_x_Entity1_EntityImplementations"));
+
+ modelBuilder.Entity()
+ .ToTable("Entity2")
+ .HasKey(t => t.Id);
+ modelBuilder.Entity()
+ .Property(t => t.Id)
+ .ValueGeneratedOnAdd()
+ .IsRequired();
+ modelBuilder.Entity()
+ .HasMany(p => p.EntityImplementations_Entity3)
+ .WithOne(p => p.Entity2);
modelBuilder.Entity()
.ToTable("EntityAbstract")
@@ -89,6 +120,22 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.Property(t => t.Test)
.HasMaxLength(255);
+ modelBuilder.Entity()
+ .HasMany(p => p.Entity2)
+ .WithMany(p => p.EntityImplementations)
+ .UsingEntity(j => j.HasOne(x => x.EntityImplementations).WithMany(x => x.Entity2_AssocClass).HasForeignKey(x => x.EntityImplementationsId)
+ , j => j.HasOne(x => x.Entity2).WithMany(x => x.EntityImplementations_AssocClass).HasForeignKey(x => x.Entity2Id)
+ , j =>
+ {
+ j.ToTable("AssocClasses");
+ j.HasKey(t => new { t.Entity2Id, t.EntityImplementationsId });
+ j.Property(t => t.Id).IsRequired();
+ j.HasIndex(t => t.Id).IsUnique();
+ });
+ modelBuilder.Entity()
+ .HasMany(p => p.Entity2_Entity3)
+ .WithOne(p => p.EntityImplementations);
+
modelBuilder.Entity()
.ToTable("EntityRelated")
.HasKey(t => t.Id);
@@ -98,9 +145,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.IsRequired();
modelBuilder.Entity()
.HasOne(p => p.EntityAbstract)
- .WithMany(p => p.EntityRelated)
- .HasForeignKey("EntityAbstractId");
- modelBuilder.Entity().Navigation(e => e.EntityAbstract).IsRequired();
+ .WithMany(p => p.EntityRelated);
OnModelCreatedImpl(modelBuilder);
}
diff --git a/src/Testing/EFCoreV5/EFCore5Net5/Generated/Entity1.generated.cs b/src/Testing/EFCoreV5/EFCore5Net5/Generated/Entity1.generated.cs
index 69b8717bd..9625dbf16 100644
--- a/src/Testing/EFCoreV5/EFCore5Net5/Generated/Entity1.generated.cs
+++ b/src/Testing/EFCoreV5/EFCore5Net5/Generated/Entity1.generated.cs
@@ -5,7 +5,7 @@
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
//
-// Produced by Entity Framework Visual Editor v3.0.4.7
+// Produced by Entity Framework Visual Editor v4.1.2.0
// Source: https://github.com/msawczyn/EFDesigner
// Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner
// Documentation: https://msawczyn.github.io/EFDesigner/
@@ -29,43 +29,15 @@ public partial class Entity1
partial void Init();
///
- /// Default constructor. Protected due to required properties, but present because EF needs it.
+ /// Default constructor
///
- protected Entity1()
+ public Entity1()
{
- Init();
- }
-
- ///
- /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving.
- ///
- public static Entity1 CreateEntity1Unsafe()
- {
- return new Entity1();
- }
-
- ///
- /// Public constructor with required data
- ///
- ///
- public Entity1(global::Testing.EntityImplementation entityimplementation)
- {
- if (entityimplementation == null) throw new ArgumentNullException(nameof(entityimplementation));
- this.EntityImplementation = entityimplementation;
- entityimplementation.Entity1 = this;
+ EntityImplementations = new System.Collections.Generic.HashSet();
Init();
}
- ///
- /// Static create function (for use in LINQ queries, etc.)
- ///
- ///
- public static Entity1 Create(global::Testing.EntityImplementation entityimplementation)
- {
- return new Entity1(entityimplementation);
- }
-
/*************************************************************************
* Properties
*************************************************************************/
@@ -83,10 +55,7 @@ public static Entity1 Create(global::Testing.EntityImplementation entityimplemen
* Navigation properties
*************************************************************************/
- ///
- /// Required
- ///
- public virtual global::Testing.EntityImplementation EntityImplementation { get; set; }
+ public virtual ICollection EntityImplementations { get; private set; }
}
}
diff --git a/src/Testing/EFCoreV5/EFCore5Net5/Generated/Entity2.generated.cs b/src/Testing/EFCoreV5/EFCore5Net5/Generated/Entity2.generated.cs
new file mode 100644
index 000000000..8cc175b2c
--- /dev/null
+++ b/src/Testing/EFCoreV5/EFCore5Net5/Generated/Entity2.generated.cs
@@ -0,0 +1,70 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated from a template.
+//
+// Manual changes to this file may cause unexpected behavior in your application.
+// Manual changes to this file will be overwritten if the code is regenerated.
+//
+// Produced by Entity Framework Visual Editor v4.1.2.0
+// Source: https://github.com/msawczyn/EFDesigner
+// Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner
+// Documentation: https://msawczyn.github.io/EFDesigner/
+// License (MIT): https://github.com/msawczyn/EFDesigner/blob/master/LICENSE
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Linq;
+using System.Runtime.CompilerServices;
+
+namespace Testing
+{
+ public partial class Entity2
+ {
+ partial void Init();
+
+ ///
+ /// Default constructor
+ ///
+ public Entity2()
+ {
+ EntityImplementations_Entity3 = new System.Collections.Generic.HashSet();
+ EntityImplementations = new System.Collections.Generic.HashSet();
+
+ Init();
+ }
+
+ /*************************************************************************
+ * Properties
+ *************************************************************************/
+
+ ///
+ /// Identity, Indexed, Required
+ /// Unique identifier
+ ///
+ [Key]
+ [Required]
+ [System.ComponentModel.Description("Unique identifier")]
+ public long Id { get; set; }
+
+ /*************************************************************************
+ * Navigation properties
+ *************************************************************************/
+
+ public virtual ICollection EntityImplementations { get; private set; }
+
+ ///
+ /// Association class for EntityImplementations
+ ///
+ [System.ComponentModel.Description("Association class for EntityImplementations")]
+ [System.ComponentModel.DataAnnotations.Display(Name="Association object for EntityImplementations")]
+ public virtual ICollection EntityImplementations_Entity3 { get; private set; }
+
+ }
+}
+
diff --git a/src/Testing/EFCoreV5/EFCore5Net5/Generated/EntityAbstract.generated.cs b/src/Testing/EFCoreV5/EFCore5Net5/Generated/EntityAbstract.generated.cs
index 730eec85d..23959b114 100644
--- a/src/Testing/EFCoreV5/EFCore5Net5/Generated/EntityAbstract.generated.cs
+++ b/src/Testing/EFCoreV5/EFCore5Net5/Generated/EntityAbstract.generated.cs
@@ -5,7 +5,7 @@
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
//
-// Produced by Entity Framework Visual Editor v3.0.4.7
+// Produced by Entity Framework Visual Editor v4.1.2.0
// Source: https://github.com/msawczyn/EFDesigner
// Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner
// Documentation: https://msawczyn.github.io/EFDesigner/
diff --git a/src/Testing/EFCoreV5/EFCore5Net5/Generated/EntityImplementation.generated.cs b/src/Testing/EFCoreV5/EFCore5Net5/Generated/EntityImplementation.generated.cs
index 312dd4630..0b91286de 100644
--- a/src/Testing/EFCoreV5/EFCore5Net5/Generated/EntityImplementation.generated.cs
+++ b/src/Testing/EFCoreV5/EFCore5Net5/Generated/EntityImplementation.generated.cs
@@ -5,7 +5,7 @@
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
//
-// Produced by Entity Framework Visual Editor v3.0.4.7
+// Produced by Entity Framework Visual Editor v4.1.2.0
// Source: https://github.com/msawczyn/EFDesigner
// Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner
// Documentation: https://msawczyn.github.io/EFDesigner/
@@ -33,6 +33,10 @@ public partial class EntityImplementation: global::Testing.EntityAbstract
///
public EntityImplementation(): base()
{
+ Entity2 = new System.Collections.Generic.HashSet();
+ Entity2_Entity3 = new System.Collections.Generic.HashSet();
+ Entity1 = new System.Collections.Generic.HashSet();
+
Init();
}
@@ -51,7 +55,16 @@ public EntityImplementation(): base()
* Navigation properties
*************************************************************************/
- public virtual global::Testing.Entity1 Entity1 { get; set; }
+ public virtual ICollection Entity1 { get; private set; }
+
+ public virtual ICollection Entity2 { get; private set; }
+
+ ///
+ /// Association class for Entity2
+ ///
+ [System.ComponentModel.Description("Association class for Entity2")]
+ [System.ComponentModel.DataAnnotations.Display(Name="Association object for Entity2")]
+ public virtual ICollection Entity2_Entity3 { get; private set; }
}
}
diff --git a/src/Testing/EFCoreV5/EFCore5Net5/Generated/EntityRelated.generated.cs b/src/Testing/EFCoreV5/EFCore5Net5/Generated/EntityRelated.generated.cs
index 0f24cbb97..59ea20ae5 100644
--- a/src/Testing/EFCoreV5/EFCore5Net5/Generated/EntityRelated.generated.cs
+++ b/src/Testing/EFCoreV5/EFCore5Net5/Generated/EntityRelated.generated.cs
@@ -5,7 +5,7 @@
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
//
-// Produced by Entity Framework Visual Editor v3.0.4.7
+// Produced by Entity Framework Visual Editor v4.1.2.0
// Source: https://github.com/msawczyn/EFDesigner
// Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner
// Documentation: https://msawczyn.github.io/EFDesigner/
diff --git a/src/Testing/EFCoreV5/EFCore5Net5/VSIntegration.ttinclude b/src/Testing/EFCoreV5/EFCore5Net5/VSIntegration.ttinclude
new file mode 100644
index 000000000..78e6fe15f
--- /dev/null
+++ b/src/Testing/EFCoreV5/EFCore5Net5/VSIntegration.ttinclude
@@ -0,0 +1,191 @@
+<#@ include file="EF6ModelGenerator.ttinclude" once="true"
+#><#@ include file="EFCore2ModelGenerator.ttinclude" once="true"
+#><#@ include file="EFCore3ModelGenerator.ttinclude" once="true"
+#><#@ include file="EFCore5ModelGenerator.ttinclude" once="true"
+#><#@ include file="EFCoreModelGenerator.ttinclude" once="true"
+#><#@ include file="EFModelFileManager.ttinclude" once="true"
+#><#@ include file="EFModelGenerator.ttinclude" once="true"
+#><#@ include file="VSIntegration.ttinclude" once="true"
+#><#@ assembly name="System.Core"
+#><#@ assembly name="System.Data.Linq"
+#><#@ assembly name="EnvDTE"
+#><#@ assembly name="System.Xml"
+#><#@ assembly name="System.Xml.Linq"
+#><#@ import namespace="System"
+#><#@ import namespace="System.IO"
+#><#@ import namespace="System.Globalization"
+#><#@ import namespace="System.Linq"
+#><#@ import namespace="System.Security"
+#><#@ import namespace="System.Text"
+#><#@ import namespace="System.Collections.Generic"
+#><#@ import namespace="System.Diagnostics.CodeAnalysis"
+#><#@ import namespace="EnvDTE"
+#><#@ import namespace="System.Data.Entity.Design.PluralizationServices"
+#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
+#><#+
+ // EFDesigner v4.1.2.0
+ // Copyright (c) 2017-2022 Michael Sawczyn
+ // https://github.com/msawczyn/EFDesigner
+
+ // this bit is based on EntityFramework Reverse POCO Code First Generator
+ // Copyright (C) Simon Hughes 2012
+ // https://github.com/sjh37/EntityFramework-Reverse-POCO-Code-First-Generator
+ //
+
+ /**************************************************
+ * Interactions with Visual Studio
+ */
+
+ public IEnumerable GetAllProjects()
+ {
+ foreach (Project project in GetSolution().Projects.OfType())
+ {
+ if (project.Kind == EnvDTE.Constants.vsProjectKindSolutionItems)
+ {
+ foreach (Project p in RecurseSolutionFolder(project))
+ yield return p;
+ }
+ else
+ yield return project;
+ }
+ }
+
+ public Project GetCurrentProject()
+ {
+ DTE dte = GetDTE();
+
+ ProjectItem projectItem = dte.Solution.FindProjectItem(Host.TemplateFile);
+
+ if (projectItem?.ContainingProject != null)
+ return projectItem.ContainingProject;
+
+ // this returns SELECTED (active) project(s) - it may be a different project than the T4 template.
+ Array activeSolutionProjects = (Array)dte.ActiveSolutionProjects;
+
+ if (activeSolutionProjects == null)
+ throw new Exception("DTE.ActiveSolutionProjects returned null");
+
+ if (activeSolutionProjects.Length > 0)
+ {
+ Project dteProject = (Project)activeSolutionProjects.GetValue(0);
+
+ if (dteProject != null)
+ return dteProject;
+ }
+
+ throw new InvalidOperationException("Error in GetCurrentProject(). Unable to find project.");
+ }
+
+ private EnvDTE.ProjectItem GetDirectoryItem(string target)
+ {
+ DTE dte = GetDTE();
+ Array projects = dte?.ActiveSolutionProjects as Array;
+ Project currentProject = projects?.GetValue(0) as Project;
+ ProjectItem targetProjectItem = null;
+
+ if (currentProject != null)
+ {
+ string rootDirectory = Path.GetDirectoryName(currentProject.FullName);
+ Directory.CreateDirectory(Path.Combine(rootDirectory, target));
+
+ Queue paths = new Queue(target.Split('\\'));
+ EnvDTE.ProjectItems currentItemList = currentProject.ProjectItems;
+ bool found = false;
+
+ while (paths.Any())
+ {
+ string path = paths.Dequeue();
+
+ for (int index = 1; index <= currentItemList.Count; ++index)
+ {
+ if (currentItemList.Item(index).Kind == EnvDTE.Constants.vsProjectItemKindPhysicalFolder)
+ {
+ if (!paths.Any())
+ targetProjectItem = currentItemList.Item(index);
+ else
+ currentItemList = currentItemList.Item(index).ProjectItems;
+
+ found = true;
+
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ ProjectItem newItem = currentItemList.AddFolder(path);
+
+ if (!paths.Any())
+ targetProjectItem = newItem;
+ else
+ currentItemList = newItem.ProjectItems;
+ }
+ }
+ }
+
+ return targetProjectItem;
+ }
+
+ public EnvDTE.DTE GetDTE()
+ {
+ IServiceProvider serviceProvider = (IServiceProvider)Host;
+
+ if (serviceProvider == null)
+ throw new Exception("Host property returned unexpected value (null)");
+
+ DTE dte = (DTE)serviceProvider.GetService(typeof(DTE));
+
+ if (dte == null)
+ throw new Exception("Unable to retrieve EnvDTE.DTE");
+
+ return dte;
+ }
+
+ private string GetProjectPath(Project project)
+ {
+ string fullProjectName = project.FullName;
+
+ if (string.IsNullOrWhiteSpace(fullProjectName))
+ return string.Empty;
+
+ try
+ {
+ FileInfo info = new FileInfo(fullProjectName);
+
+ return info.Directory != null ? info.Directory.FullName : string.Empty;
+ }
+ catch
+ {
+ WriteLine("// Project " + fullProjectName + " excluded.");
+
+ return string.Empty;
+ }
+ }
+
+ public EnvDTE.Solution GetSolution()
+ {
+ return GetDTE().Solution;
+ }
+
+ private IEnumerable RecurseSolutionFolder(Project project)
+ {
+ if (project.ProjectItems == null)
+ yield break;
+
+ foreach (Project subProject in project.ProjectItems
+ .Cast()
+ .Select(projectItem => projectItem.SubProject)
+ .Where(subProject => subProject != null))
+ {
+ if (subProject.Kind == EnvDTE.Constants.vsProjectKindSolutionItems)
+ {
+ foreach (Project p in RecurseSolutionFolder(subProject))
+ yield return p;
+ }
+ else
+ yield return subProject;
+ }
+ }
+
+
+#>
diff --git a/src/Testing/Sandbox/Sandbox_EFCore/AppDbContext.generated.cs b/src/Testing/Sandbox/Sandbox_EFCore/AppDbContext.generated.cs
index deb7b0e71..503905eac 100644
--- a/src/Testing/Sandbox/Sandbox_EFCore/AppDbContext.generated.cs
+++ b/src/Testing/Sandbox/Sandbox_EFCore/AppDbContext.generated.cs
@@ -5,7 +5,7 @@
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
//
-// Produced by Entity Framework Visual Editor v3.0.7.1
+// Produced by Entity Framework Visual Editor v4.1.2.0
// Source: https://github.com/msawczyn/EFDesigner
// Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner
// Documentation: https://msawczyn.github.io/EFDesigner/
@@ -25,6 +25,8 @@ namespace SureImpact.Data.Framework
public partial class AppDbContext : DbContext
{
#region DbSets
+ public virtual Microsoft.EntityFrameworkCore.DbSet Entity1 { get; set; }
+ public virtual Microsoft.EntityFrameworkCore.DbSet Entity2 { get; set; }
public virtual Microsoft.EntityFrameworkCore.DbSet TestDatas { get; set; }
public virtual Microsoft.EntityFrameworkCore.DbSet TestViews { get; set; }
@@ -81,6 +83,25 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.HasDefaultSchema("dbo");
+ modelBuilder.Entity()
+ .ToTable("Entity1")
+ .HasKey(t => t.Id);
+ modelBuilder.Entity()
+ .Property(t => t.Id)
+ .ValueGeneratedOnAdd()
+ .IsRequired();
+ modelBuilder.Entity()
+ .Property(t => t.TestString)
+ .HasMaxLength(200)
+ .IsRequired();
+ modelBuilder.Entity().HasIndex(t => t.TestString)
+ .IsUnique();
+ modelBuilder.Entity()
+ .HasMany(p => p.TestDatas_Entity2)
+ .WithOne(p => p.Entity1)
+ .HasForeignKey(k => k.TestDatasId)
+ .IsRequired();
+
modelBuilder.Entity()
.ToTable("TestDatas")
.HasKey(t => t.Id);
@@ -94,9 +115,24 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.Property(t => t.Id)
.ValueGeneratedOnAdd()
.IsRequired();
+ modelBuilder.Entity()
+ .HasMany(p => p.Entity1)
+ .WithMany(p => p.TestDatas)
+ .UsingEntity(x => x.ToTable("Entity1_TestDatas_x_TestData_Entity1"));
+ modelBuilder.Entity().Navigation(e => e.Entity1)
+ .HasField("_entity1")
+ .Metadata.SetPropertyAccessMode(PropertyAccessMode.FieldDuringConstruction);
+ modelBuilder.Entity().Navigation(e => e.TestDatas)
+ .HasField("_testDatas")
+ .Metadata.SetPropertyAccessMode(PropertyAccessMode.FieldDuringConstruction);
+ modelBuilder.Entity()
+ .HasMany(p => p.Entity1_Entity2)
+ .WithOne(p => p.TestDatas)
+ .HasForeignKey(k => k.Entity1Id)
+ .IsRequired();
modelBuilder.Entity()
- .ToTable("TestViews");
+ .ToView("TestView");
modelBuilder.Entity()
.Property(t => t.TestString)
.HasMaxLength(200)
diff --git a/src/Testing/Sandbox/Sandbox_EFCore/EFModel1.efmodel b/src/Testing/Sandbox/Sandbox_EFCore/EFModel1.efmodel
index 229e2c6ef..25fc58525 100644
--- a/src/Testing/Sandbox/Sandbox_EFCore/EFModel1.efmodel
+++ b/src/Testing/Sandbox/Sandbox_EFCore/EFModel1.efmodel
@@ -1,5 +1,5 @@
-
+
@@ -18,6 +18,9 @@
+
+
+
@@ -27,6 +30,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Testing/Sandbox/Sandbox_EFCore/EFModel1.efmodel.diagramx b/src/Testing/Sandbox/Sandbox_EFCore/EFModel1.efmodel.diagramx
index da0cb5190..578ecaf05 100644
--- a/src/Testing/Sandbox/Sandbox_EFCore/EFModel1.efmodel.diagramx
+++ b/src/Testing/Sandbox/Sandbox_EFCore/EFModel1.efmodel.diagramx
@@ -3,25 +3,25 @@
-
+
-
-
+
+
-
+
-
-
+
+
-
+
@@ -29,6 +29,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Testing/Sandbox/Sandbox_EFCore/Entity1.generated.cs b/src/Testing/Sandbox/Sandbox_EFCore/Entity1.generated.cs
new file mode 100644
index 000000000..cf74a752d
--- /dev/null
+++ b/src/Testing/Sandbox/Sandbox_EFCore/Entity1.generated.cs
@@ -0,0 +1,126 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated from a template.
+//
+// Manual changes to this file may cause unexpected behavior in your application.
+// Manual changes to this file will be overwritten if the code is regenerated.
+//
+// Produced by Entity Framework Visual Editor v4.1.2.0
+// Source: https://github.com/msawczyn/EFDesigner
+// Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner
+// Documentation: https://msawczyn.github.io/EFDesigner/
+// License (MIT): https://github.com/msawczyn/EFDesigner/blob/master/LICENSE
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Linq;
+using System.Runtime.CompilerServices;
+
+namespace SureImpact.Data.Framework
+{
+ public partial class Entity1
+ {
+ partial void Init();
+
+ ///
+ /// Default constructor. Protected due to required properties, but present because EF needs it.
+ ///
+ protected Entity1()
+ {
+ TestDatas_Entity2 = new System.Collections.Generic.HashSet();
+ _testDatas = new System.Collections.Generic.HashSet();
+
+ Init();
+ }
+
+ ///
+ /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving.
+ ///
+ public static Entity1 CreateEntity1Unsafe()
+ {
+ return new Entity1();
+ }
+
+ ///
+ /// Public constructor with required data
+ ///
+ /// Test string
+ public Entity1(string teststring)
+ {
+ if (string.IsNullOrEmpty(teststring)) throw new ArgumentNullException(nameof(teststring));
+ this.TestString = teststring;
+
+ TestDatas_Entity2 = new System.Collections.Generic.HashSet();
+ _testDatas = new System.Collections.Generic.HashSet();
+ Init();
+ }
+
+ ///
+ /// Static create function (for use in LINQ queries, etc.)
+ ///
+ /// Test string
+ public static Entity1 Create(string teststring)
+ {
+ return new Entity1(teststring);
+ }
+
+ /*************************************************************************
+ * Properties
+ *************************************************************************/
+
+ ///
+ /// Identity, Indexed, Required
+ /// Unique identifier
+ ///
+ [Key]
+ [Required]
+ [System.ComponentModel.Description("Unique identifier")]
+ public long Id { get; set; }
+
+ ///
+ /// Indexed, Required, Max length = 200
+ /// Test string
+ ///
+ [Required]
+ [MaxLength(200)]
+ [StringLength(200)]
+ [System.ComponentModel.Description("Test string")]
+ public string TestString { get; set; }
+
+ /*************************************************************************
+ * Navigation properties
+ *************************************************************************/
+
+ ///
+ /// Backing field for TestDatas
+ ///
+ protected ICollection _testDatas;
+
+ public virtual ICollection TestDatas
+ {
+ get
+ {
+ return _testDatas;
+ }
+ private set
+ {
+ _testDatas = value;
+ }
+ }
+
+ ///
+ /// Association class for TestDatas
+ ///
+ [System.ComponentModel.Description("Association class for TestDatas")]
+ [System.ComponentModel.DataAnnotations.Display(Name="Association object for TestDatas")]
+ public virtual ICollection TestDatas_Entity2 { get; private set; }
+
+ }
+}
+
diff --git a/src/Testing/Sandbox/Sandbox_EFCore/Entity2.generated.cs b/src/Testing/Sandbox/Sandbox_EFCore/Entity2.generated.cs
new file mode 100644
index 000000000..69e1beef5
--- /dev/null
+++ b/src/Testing/Sandbox/Sandbox_EFCore/Entity2.generated.cs
@@ -0,0 +1,139 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated from a template.
+//
+// Manual changes to this file may cause unexpected behavior in your application.
+// Manual changes to this file will be overwritten if the code is regenerated.
+//
+// Produced by Entity Framework Visual Editor v4.1.2.0
+// Source: https://github.com/msawczyn/EFDesigner
+// Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner
+// Documentation: https://msawczyn.github.io/EFDesigner/
+// License (MIT): https://github.com/msawczyn/EFDesigner/blob/master/LICENSE
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Linq;
+using System.Runtime.CompilerServices;
+
+namespace SureImpact.Data.Framework
+{
+ public partial class Entity2
+ {
+ partial void Init();
+
+ ///
+ /// Default constructor. Protected due to required properties, but present because EF needs it.
+ ///
+ protected Entity2()
+ {
+ Init();
+ }
+
+ ///
+ /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving.
+ ///
+ public static Entity2 CreateEntity2Unsafe()
+ {
+ return new Entity2();
+ }
+
+ ///
+ /// Public constructor with required data
+ ///
+ /// Unique identifier
+ /// Foreign key for TestData.Entity1_Entity2 <--> Entity2.TestDatas.
+ /// Foreign key for Entity1.TestDatas_Entity2 <--> Entity2.Entity1.
+ /// Association class for TestDatas
+ /// Association class for Entity1
+ public Entity2(long id, long entity1id, long testdatasid, global::SureImpact.Data.Framework.TestData testdatas, global::SureImpact.Data.Framework.Entity1 entity1)
+ {
+ this.Id = id;
+
+ this.Entity1Id = entity1id;
+
+ this.TestDatasId = testdatasid;
+
+ if (testdatas == null) throw new ArgumentNullException(nameof(testdatas));
+ this.TestDatas = testdatas;
+ testdatas.Entity1_Entity2.Add(this);
+
+ if (entity1 == null) throw new ArgumentNullException(nameof(entity1));
+ this.Entity1 = entity1;
+ entity1.TestDatas_Entity2.Add(this);
+
+ Init();
+ }
+
+ ///
+ /// Static create function (for use in LINQ queries, etc.)
+ ///
+ /// Unique identifier
+ /// Foreign key for TestData.Entity1_Entity2 <--> Entity2.TestDatas.
+ /// Foreign key for Entity1.TestDatas_Entity2 <--> Entity2.Entity1.
+ /// Association class for TestDatas
+ /// Association class for Entity1
+ public static Entity2 Create(long id, long entity1id, long testdatasid, global::SureImpact.Data.Framework.TestData testdatas, global::SureImpact.Data.Framework.Entity1 entity1)
+ {
+ return new Entity2(id, entity1id, testdatasid, testdatas, entity1);
+ }
+
+ /*************************************************************************
+ * Properties
+ *************************************************************************/
+
+ ///
+ /// Identity, Indexed, Required
+ /// Foreign key for TestData.Entity1_Entity2 <--> Entity2.TestDatas.
+ ///
+ [Key]
+ [Required]
+ [System.ComponentModel.Description("Foreign key for TestData.Entity1_Entity2 <--> Entity2.TestDatas. ")]
+ public long Entity1Id { get; set; }
+
+ ///
+ /// Indexed, Required
+ /// Unique identifier
+ ///
+ [Required]
+ [System.ComponentModel.Description("Unique identifier")]
+ public long Id { get; set; }
+
+ ///
+ /// Identity, Indexed, Required
+ /// Foreign key for Entity1.TestDatas_Entity2 <--> Entity2.Entity1.
+ ///
+ [Key]
+ [Required]
+ [System.ComponentModel.Description("Foreign key for Entity1.TestDatas_Entity2 <--> Entity2.Entity1. ")]
+ public long TestDatasId { get; set; }
+
+ /*************************************************************************
+ * Navigation properties
+ *************************************************************************/
+
+ ///
+ /// Required<br/>
+ /// Association class for Entity1
+ ///
+ [System.ComponentModel.Description("Association class for Entity1")]
+ [System.ComponentModel.DataAnnotations.Display(Name="Association object for Entity1")]
+ public virtual global::SureImpact.Data.Framework.Entity1 Entity1 { get; set; }
+
+ ///
+ /// Required<br/>
+ /// Association class for TestDatas
+ ///
+ [System.ComponentModel.Description("Association class for TestDatas")]
+ [System.ComponentModel.DataAnnotations.Display(Name="Association object for TestDatas")]
+ public virtual global::SureImpact.Data.Framework.TestData TestDatas { get; set; }
+
+ }
+}
+
diff --git a/src/Testing/Sandbox/Sandbox_EFCore/Sandbox_EFCore.csproj b/src/Testing/Sandbox/Sandbox_EFCore/Sandbox_EFCore.csproj
index bb3e1e363..b7f4e19d6 100644
--- a/src/Testing/Sandbox/Sandbox_EFCore/Sandbox_EFCore.csproj
+++ b/src/Testing/Sandbox/Sandbox_EFCore/Sandbox_EFCore.csproj
@@ -50,6 +50,12 @@
True
EFModel1.tt
+
+ EFModel1.tt
+
+
+ EFModel1.tt
+
EFModel1.tt
diff --git a/src/Testing/Sandbox/Sandbox_EFCore/TestData.generated.cs b/src/Testing/Sandbox/Sandbox_EFCore/TestData.generated.cs
index b483b6259..61b78a153 100644
--- a/src/Testing/Sandbox/Sandbox_EFCore/TestData.generated.cs
+++ b/src/Testing/Sandbox/Sandbox_EFCore/TestData.generated.cs
@@ -5,7 +5,7 @@
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
//
-// Produced by Entity Framework Visual Editor v3.0.7.1
+// Produced by Entity Framework Visual Editor v4.1.2.0
// Source: https://github.com/msawczyn/EFDesigner
// Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner
// Documentation: https://msawczyn.github.io/EFDesigner/
@@ -33,6 +33,9 @@ public partial class TestData
///
protected TestData()
{
+ _entity1 = new System.Collections.Generic.HashSet();
+ Entity1_Entity2 = new System.Collections.Generic.HashSet();
+
Init();
}
@@ -53,6 +56,8 @@ public TestData(string teststring)
if (string.IsNullOrEmpty(teststring)) throw new ArgumentNullException(nameof(teststring));
this.TestString = teststring;
+ _entity1 = new System.Collections.Generic.HashSet();
+ Entity1_Entity2 = new System.Collections.Generic.HashSet();
Init();
}
@@ -69,6 +74,15 @@ public static TestData Create(string teststring)
* Properties
*************************************************************************/
+ ///
+ /// Identity, Indexed, Required
+ /// Unique identifier
+ ///
+ [Key]
+ [Required]
+ [System.ComponentModel.Description("Unique identifier")]
+ public long Id { get; set; }
+
///
/// Indexed, Required, Max length = 200
/// Test string
@@ -79,14 +93,33 @@ public static TestData Create(string teststring)
[System.ComponentModel.Description("Test string")]
public string TestString { get; set; }
+ /*************************************************************************
+ * Navigation properties
+ *************************************************************************/
+
///
- /// Identity, Indexed, Required
- /// Unique identifier
+ /// Backing field for Entity1
///
- [Key]
- [Required]
- [System.ComponentModel.Description("Unique identifier")]
- public long Id { get; set; }
+ protected ICollection _entity1;
+
+ public virtual ICollection Entity1
+ {
+ get
+ {
+ return _entity1;
+ }
+ private set
+ {
+ _entity1 = value;
+ }
+ }
+
+ ///
+ /// Association class for Entity1
+ ///
+ [System.ComponentModel.Description("Association class for Entity1")]
+ [System.ComponentModel.DataAnnotations.Display(Name="Association object for Entity1")]
+ public virtual ICollection Entity1_Entity2 { get; private set; }
}
}
diff --git a/src/Testing/Sandbox/Sandbox_EFCore/TestView.generated.cs b/src/Testing/Sandbox/Sandbox_EFCore/TestView.generated.cs
index 25eb95f9d..ba9f4810f 100644
--- a/src/Testing/Sandbox/Sandbox_EFCore/TestView.generated.cs
+++ b/src/Testing/Sandbox/Sandbox_EFCore/TestView.generated.cs
@@ -5,7 +5,7 @@
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
//
-// Produced by Entity Framework Visual Editor v3.0.7.1
+// Produced by Entity Framework Visual Editor v4.1.2.0
// Source: https://github.com/msawczyn/EFDesigner
// Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=michaelsawczyn.EFDesigner
// Documentation: https://msawczyn.github.io/EFDesigner/
diff --git a/src/Utilities/EF6Parser/Parser.cs b/src/Utilities/EF6Parser/Parser.cs
index d7c8f3a10..36a458388 100644
--- a/src/Utilities/EF6Parser/Parser.cs
+++ b/src/Utilities/EF6Parser/Parser.cs
@@ -419,7 +419,7 @@ private ModelClass ProcessEntity(string entityFullName, EntityType oSpaceType, E
IsAbstract = oSpaceType.Abstract,
BaseClass = GetTypeFullName(oSpaceType.BaseType?.Name),
CustomInterfaces = type.GetInterfaces().Any()
- ? string.Join(",", type.GetInterfaces().Select(GetTypeFullName))
+ ? string.Join(",", type.GetInterfaces().Select(GetTypeFullName).Where(s => s != null))
: null,
IsDependentType = false,
CustomAttributes = customAttributes.Length > 2
diff --git a/src/Utilities/EF6Parser/Properties/AssemblyInfo.cs b/src/Utilities/EF6Parser/Properties/AssemblyInfo.cs
index d3b574be2..c216129cd 100644
--- a/src/Utilities/EF6Parser/Properties/AssemblyInfo.cs
+++ b/src/Utilities/EF6Parser/Properties/AssemblyInfo.cs
@@ -17,6 +17,6 @@
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("3.0.5")]
-[assembly: AssemblyFileVersion("3.0.5")]
+[assembly: AssemblyVersion("4.1.2.0")]
+[assembly: AssemblyFileVersion("4.1.2.0")]
[assembly: ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)]
diff --git a/src/Utilities/EFCore2Parser/Parser.cs b/src/Utilities/EFCore2Parser/Parser.cs
index 5270b12ea..6ff5d8963 100644
--- a/src/Utilities/EFCore2Parser/Parser.cs
+++ b/src/Utilities/EFCore2Parser/Parser.cs
@@ -225,7 +225,7 @@ private ModelClass ProcessEntity(IEntityType entityType, ModelRoot modelRoot)
result.CustomAttributes = GetCustomAttributes(type.CustomAttributes);
result.CustomInterfaces = type.GetInterfaces().Any()
- ? string.Join(",", type.GetInterfaces().Select(GetTypeFullName))
+ ? string.Join(",", type.GetInterfaces().Select(GetTypeFullName).Where(s => s != null))
: null;
result.Properties = entityType.GetDeclaredProperties()
diff --git a/src/Utilities/EFCore2Parser/Properties/AssemblyInfo.cs b/src/Utilities/EFCore2Parser/Properties/AssemblyInfo.cs
index a4aec548f..648aa37aa 100644
--- a/src/Utilities/EFCore2Parser/Properties/AssemblyInfo.cs
+++ b/src/Utilities/EFCore2Parser/Properties/AssemblyInfo.cs
@@ -17,6 +17,6 @@
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("3.0.5")]
-[assembly: AssemblyFileVersion("3.0.5")]
+[assembly: AssemblyVersion("4.1.2.0")]
+[assembly: AssemblyFileVersion("4.1.2.0")]
[assembly: ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)]
diff --git a/src/Utilities/EFCore3Parser/Parser.cs b/src/Utilities/EFCore3Parser/Parser.cs
index 9a269d3c0..cdcd45cab 100644
--- a/src/Utilities/EFCore3Parser/Parser.cs
+++ b/src/Utilities/EFCore3Parser/Parser.cs
@@ -220,7 +220,7 @@ private ModelClass ProcessEntity(IEntityType entityType, ModelRoot modelRoot)
result.CustomAttributes = GetCustomAttributes(type.CustomAttributes);
result.CustomInterfaces = type.GetInterfaces().Any()
- ? string.Join(",", type.GetInterfaces().Select(GetTypeFullName))
+ ? string.Join(",", type.GetInterfaces().Select(GetTypeFullName).Where(s => s != null))
: null;
result.Properties = entityType.GetDeclaredProperties()
diff --git a/src/Utilities/EFCore3Parser/Properties/AssemblyInfo.cs b/src/Utilities/EFCore3Parser/Properties/AssemblyInfo.cs
index 1a0edaf93..b78b4a645 100644
--- a/src/Utilities/EFCore3Parser/Properties/AssemblyInfo.cs
+++ b/src/Utilities/EFCore3Parser/Properties/AssemblyInfo.cs
@@ -17,6 +17,6 @@
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("3.0.5")]
-[assembly: AssemblyFileVersion("3.0.5")]
+[assembly: AssemblyVersion("4.1.2.0")]
+[assembly: AssemblyFileVersion("4.1.2.0")]
[assembly: ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)]
diff --git a/src/Utilities/EFCore5Parser/Parser.cs b/src/Utilities/EFCore5Parser/Parser.cs
index c2d135403..3917a4d7a 100644
--- a/src/Utilities/EFCore5Parser/Parser.cs
+++ b/src/Utilities/EFCore5Parser/Parser.cs
@@ -220,7 +220,7 @@ private ModelClass ProcessEntity(IEntityType entityType, ModelRoot modelRoot)
result.CustomAttributes = GetCustomAttributes(type.CustomAttributes);
result.CustomInterfaces = type.GetInterfaces().Any()
- ? string.Join(",", type.GetInterfaces().Select(GetTypeFullName))
+ ? string.Join(",", type.GetInterfaces().Select(GetTypeFullName).Where(s => s != null))
: null;
result.Properties = entityType.GetDeclaredProperties()
diff --git a/src/Utilities/EFCore5Parser/Properties/AssemblyInfo.cs b/src/Utilities/EFCore5Parser/Properties/AssemblyInfo.cs
index e21d45095..1c8258a99 100644
--- a/src/Utilities/EFCore5Parser/Properties/AssemblyInfo.cs
+++ b/src/Utilities/EFCore5Parser/Properties/AssemblyInfo.cs
@@ -17,5 +17,5 @@
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("3.0.5")]
-[assembly: AssemblyFileVersion("3.0.5")]
+[assembly: AssemblyVersion("4.1.2.0")]
+[assembly: AssemblyFileVersion("4.1.2.0")]
diff --git a/src/Utilities/ParsingModels/AssemblyInfo.cs b/src/Utilities/ParsingModels/AssemblyInfo.cs
index a38fb2452..50c8d7d71 100644
--- a/src/Utilities/ParsingModels/AssemblyInfo.cs
+++ b/src/Utilities/ParsingModels/AssemblyInfo.cs
@@ -19,6 +19,6 @@
[assembly: Guid("fb2035a3-09f5-43ff-8545-3af8b814b405")]
-[assembly: AssemblyVersion("3.1.0.0")]
-[assembly: AssemblyFileVersion("3.1.0.0")]
+[assembly: AssemblyVersion("4.1.2.0")]
+[assembly: AssemblyFileVersion("4.1.2.0")]
[assembly: ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)]
diff --git a/src/Utilities/ParsingModels/ParserBase.cs b/src/Utilities/ParsingModels/ParserBase.cs
index 8436f146b..db3bbdfbe 100644
--- a/src/Utilities/ParsingModels/ParserBase.cs
+++ b/src/Utilities/ParsingModels/ParserBase.cs
@@ -12,11 +12,14 @@ public abstract class ParserBase
protected static string GetTypeFullName(Type type)
{
- return GetTypeFullName(type.FullName);
+ return GetTypeFullName(type?.FullName);
}
protected static string GetTypeFullName(string fullName)
{
+ if (string.IsNullOrWhiteSpace(fullName))
+ return null;
+
Match m = TypeNameRegex.Match(fullName);
if (m.Success)