Skip to content
This repository has been archived by the owner on Jan 16, 2024. It is now read-only.

Commit

Permalink
3.0.0.preview1
Browse files Browse the repository at this point in the history
  • Loading branch information
msawczyn committed Nov 19, 2020
1 parent 481d33d commit 8b12b5e
Show file tree
Hide file tree
Showing 40 changed files with 704 additions and 399 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,32 @@ to <a href="https://www.jetbrains.com/?from=EFDesigner"><img src="https://msawcz

### Change Log

**3.0.prerelease1**
- New support EFCore5.X (available when selecting EFCore output with version >= 5)
- Added `System.Net.IPAddress` and `System.Net.NetworkInformation.PhysicalAddress` to the list of available property types
- Added ability to specify both default database collation and a collation override at the property level
- Many-to-many bidirectional associations are now allowed
- Any property type can now be used as an identity
- Can now customize backing field names for non-AutoProperty properties
- Properties with backing fields (i.e., non-AutoProperty properties) can now choose how EF will read/write those values (see https://docs.microsoft.com/en-us/ef/core/modeling/backing-field).
- Added support for keyless entity types created by defining queries
- Added support for keyless entity types coming from database views
- Fixed inability to paste enumerations using diagram copy/paste
- Changing an identity property's type now changes the type of any defined foreign-key properties pointing to that identity property
- Title text color didn't always change when class/enum fill color changed in the diagram
- Selecting tabs or spaces for indentation in generated code has been moved to a property on the designer surface.
- Added `ModelRoot.IsEFCore5Plus` convenience property. It can be used in custom T4 edits
- Added ability to globally add and remove exposed foreign key properties to all modeled entities (via menu command) (see https://github.com/msawczyn/EFDesigner/issues/223)
- Added ability to choose to place newly imported model elements on the diagram where they were dropped. Caution: this can be EXTREMELY slow for large imports. (see https://github.com/msawczyn/EFDesigner/issues/225)
- Possibly breaking changes:
- T4 template structure has been changed drastically to simplify managing code generation for the various EF versions.
If customized T4 templates have been added to a project, they'll still work, but enhancements will continue to be made only to the new, more
object-oriented, T4 structure. Updating the the model's .tt file to use the new template structure is quite simple; details will be in the documentation
at https://msawczyn.github.io/EFDesigner/Customizing.html
- Unfinished:
- Regression testing for EF6, EFCore2 and EFCore3 code generation.
- Regression testing for importing compiled assemblies

**2.0.5.7**
- Added ability to select tabs or spaces for indentation in generated code (Tools/Options/Entity Framework Visual Editor/Visual Editor Options) (See https://github.com/msawczyn/EFDesigner/issues/221)
- Fixed an issue with changing visual grid size on design surface.
Expand Down
12 changes: 8 additions & 4 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
3.0
3.0.prerelease1
- New support EFCore5.X (available when selecting EFCore output with version >= 5)
- Added System.Net.IPAddress and System.Net.NetworkInformation.PhysicalAddress to the list of available property types
- Added ability to specify both default database collation and a collation override at the property level
- Many-to-many associations are now allowed
- Added code generation for classes as property bags (Dictionary<string,object>)
- Many-to-many bidirectional associations are now allowed
- Any property type can now be used as an identity
- Can now customize backing field names for non-AutoProperty properties
- Properties with backing fields (i.e., non-AutoProperty properties) can now choose how EF will read/write those values (see https://docs.microsoft.com/en-us/ef/core/modeling/backing-field).
Expand All @@ -14,11 +13,16 @@
- Title text color didn't always change when class/enum fill color changed in the diagram
- Selecting tabs or spaces for indentation in generated code has been moved to a property on the designer surface.
- Added ModelRoot.IsEFCore5Plus convenience property. It can be used in custom T4 edits
- Added ability to globally add and remove exposed foreign key properties to all modeled entities (via menu command) (see https://github.com/msawczyn/EFDesigner/issues/223)
- Added ability to choose to place newly imported model elements on the diagram where they were dropped. Caution: this can be EXTREMELY slow for large imports. (see https://github.com/msawczyn/EFDesigner/issues/225)
- Possibly breaking changes:
- T4 template structure has been changed drastically to simplify managing code generation for the various EF versions.
If customized T4 templates have been added to a project, they'll still work, but enhancements will continue to be made only to the new, more
object-oriented, T4 structure. Updating the the model's .tt file to use the new template structure is quite simple; details are in the documentation
object-oriented, T4 structure. Updating the the model's .tt file to use the new template structure is quite simple; details will be in the documentation
at https://msawczyn.github.io/EFDesigner/Customizing.html
- Unfinished:
- Regression testing for EF6, EFCore2 and EFCore3 code generation
- Regression testing for importing compiled assemblies

2.0.5.7
- Added ability to select tabs or spaces for indentation in generated code (Tools/Options/Entity Framework Visual Editor/Visual Editor Options) (See https://github.com/msawczyn/EFDesigner/issues/221)
Expand Down
Binary file modified dist/Sawczyn.EFDesigner.EFModel.DslPackage.vsix
Binary file not shown.
113 changes: 100 additions & 13 deletions src/Dsl/CustomCode/Partials/Association.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,32 +169,80 @@ public void RedrawItem()

#endregion

[ValidationMethod(ValidationCategories.Save | ValidationCategories.Menu)]
private void DetectUnsupportedCardinalities(ValidationContext context)
internal bool AllCardinalitiesAreValid(out string errorMessage)
{
ModelRoot modelRoot = Store.ElementDirectory.FindElements<ModelRoot>().FirstOrDefault();
ModelRoot modelRoot = Source.ModelRoot;
errorMessage = null;

if (Source.IsDependentType)
if (modelRoot.IsEFCore5Plus)
{
if (!modelRoot.IsEFCore5Plus)
if (this is UnidirectionalAssociation && Is(Multiplicity.ZeroMany, Multiplicity.ZeroMany))
{
if (SourceMultiplicity != Multiplicity.One || TargetMultiplicity != Multiplicity.ZeroOne)
context.LogError($"The association from {Source.Name} to {Target.Name} must be 1..0-1", "AEUnsupportedMultiplicity", this);
errorMessage = $"{GetDisplayText()}: many-to-many unidirectional associations are not yet supported in Entity Framework Core.";
return false;
}
}
else if (Target.IsDependentType)
else
{
if (this is UnidirectionalAssociation && Source.IsDependent() && !Target.IsDependent())
{
errorMessage = $"{GetDisplayText()}: dependent objects can't have associations to entities";
return false;
}
}

if (Source.IsDependentType)
{
if (TargetMultiplicity == Multiplicity.ZeroMany)
{
errorMessage = $"{GetDisplayText()}: There can only be one owner in a dependent association";
return false;
}

if (!modelRoot.IsEFCore5Plus)
{
if (TargetMultiplicity != Multiplicity.One || SourceMultiplicity != Multiplicity.ZeroOne)
context.LogError($"The association from {Target.Name} to {Source.Name} must be 1..0-1", "AEUnsupportedMultiplicity", this);
{
errorMessage = $"{GetDisplayText()}: The association from {Source.Name} to {Target.Name} must be 1..0-1";
return false;
}
}
}
else
else if (Target.IsDependentType)
{
if (modelRoot.IsEFCore5Plus && this is UnidirectionalAssociation u && Is(Multiplicity.ZeroMany, Multiplicity.ZeroMany))
context.LogError($"{GetDisplayText()}: Many-to-many unidirectional associations are not yet supported in Entity Framework Core.", "AEUnsupportedMultiplicity", this);
if (SourceMultiplicity == Multiplicity.ZeroMany)
{
errorMessage = $"{GetDisplayText()}: There can only be one owner in a dependent association";
return false;
}

if (modelRoot.IsEFCore5Plus)
{
if (this is UnidirectionalAssociation && TargetMultiplicity == Multiplicity.ZeroMany)
{
errorMessage = $"{GetDisplayText()}: to-many associations to dependent objects must be bidirectional";
return false;
}
}
else
{
if (SourceMultiplicity != Multiplicity.One || TargetMultiplicity != Multiplicity.ZeroOne)
{
errorMessage = $"{GetDisplayText()}: The association from {Target.Name} to {Source.Name} must be 1..0-1";
return false;
}
}
}

return true;
}

[ValidationMethod(ValidationCategories.Save | ValidationCategories.Menu)]
// ReSharper disable once UnusedMember.Local
private void ValidateMultiplicity(ValidationContext context)
{
if (!AllCardinalitiesAreValid(out string errorMessage))
context.LogError(errorMessage, "AEUnsupportedMultiplicity", this);
}

[ValidationMethod(ValidationCategories.Open | ValidationCategories.Save | ValidationCategories.Menu)]
Expand Down Expand Up @@ -263,6 +311,46 @@ internal IEnumerable<ModelAttribute> GetFKAutoIdentityErrors()
.ToList();
}

public virtual IEnumerable<string> CreateForeignKeys()
{
IEnumerable<string> result = null;

if (Principal != null && Dependent != null && string.IsNullOrWhiteSpace(FKPropertyName))
result = Principal.AllIdentityAttributes.Select(identity => $"{'"'}{CreateShadowPropertyName(identity)}{'"'}");

return result;
}

public string CreateShadowPropertyName(ModelAttribute identityAttribute)
{
string GetShadowPropertyName(string nameBase)
{
if (SourceRole == EndpointRole.Dependent)
return $"{nameBase}{identityAttribute.Name}";

if (this is BidirectionalAssociation)
return $"{nameBase}{identityAttribute.Name}";

return $"{nameBase}_{identityAttribute.Name}";
}

string GetShadowPropertyNameBase()
{
if (SourceRole == EndpointRole.Dependent)
return TargetPropertyName;

if (this is BidirectionalAssociation b)
return b.SourcePropertyName;

return $"{Source.Name}_{TargetPropertyName}";
}

string shadowNameBase = GetShadowPropertyNameBase();
string shadowPropertyName = GetShadowPropertyName(shadowNameBase);

return shadowPropertyName;
}

[ValidationMethod(ValidationCategories.Save | ValidationCategories.Load | ValidationCategories.Menu)]
[UsedImplicitly]
private void FKPropertiesInvalidWithoutDependentEnd(ValidationContext context)
Expand Down Expand Up @@ -629,6 +717,5 @@ protected override void OnValueChanged(Association element, Multiplicity oldValu
element.Store.DomainDataDirectory.GetDomainProperty(TargetMultiplicityDisplayDomainPropertyId).NotifyValueChange(element);
}
}

}
}
32 changes: 23 additions & 9 deletions src/Dsl/CustomCode/Partials/AssociationConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public override string GetToolTipText(DiagramItem item)
: string.Empty;
}


/// <summary>
/// Gets or sets the decorator on the From end of the relationship.
/// </summary>
Expand All @@ -50,15 +51,17 @@ public override LinkDecorator DecoratorFrom

if (association.Target.IsDependentType)
{
LinkDecorator decorator = (association.SourceMultiplicity == Multiplicity.One ? LinkDecorator.DecoratorFilledDiamond : LinkDecorator.DecoratorEmptyDiamond);
LinkDecorator decorator = association.SourceMultiplicity == Multiplicity.One
? LinkDecorator.DecoratorFilledDiamond
: LinkDecorator.DecoratorEmptyDiamond;

if (base.DecoratorFrom != decorator)
SetDecorators(decorator, new SizeD(0.15,0.15), DecoratorTo, DefaultDecoratorSize, true);
SetDecorators(decorator, new SizeD(0.15,0.15), base.DecoratorTo, DefaultDecoratorSize, true);
}
else
{
if (base.DecoratorFrom != null)
SetDecorators(null, DefaultDecoratorSize, DecoratorTo, DefaultDecoratorSize, true);
SetDecorators(null, DefaultDecoratorSize, base.DecoratorTo, DefaultDecoratorSize, true);
}

return base.DecoratorFrom;
Expand All @@ -81,16 +84,27 @@ public override LinkDecorator DecoratorTo

if (association.Source.IsDependentType)
{
LinkDecorator decorator = (association.TargetMultiplicity == Multiplicity.One ? LinkDecorator.DecoratorFilledDiamond : LinkDecorator.DecoratorEmptyDiamond);
LinkDecorator decorator = association.TargetMultiplicity == Multiplicity.One
? LinkDecorator.DecoratorFilledDiamond
: LinkDecorator.DecoratorEmptyDiamond;

if (base.DecoratorTo != decorator)
SetDecorators(DecoratorFrom, DefaultDecoratorSize, decorator, new SizeD(0.15,0.15), true);
SetDecorators(base.DecoratorFrom, DefaultDecoratorSize, decorator, new SizeD(0.15,0.15), true);
}
else
{
if (association is UnidirectionalAssociation && base.DecoratorTo != LinkDecorator.DecoratorEmptyArrow)
SetDecorators(DecoratorFrom, DefaultDecoratorSize, LinkDecorator.DecoratorEmptyArrow, new SizeD(0.1,0.1), true);
else if (association is BidirectionalAssociation && base.DecoratorTo != null)
SetDecorators(null, DefaultDecoratorSize, null, DefaultDecoratorSize, true);
switch (association)
{
case UnidirectionalAssociation _ when base.DecoratorTo != LinkDecorator.DecoratorEmptyArrow:
SetDecorators(base.DecoratorFrom, DefaultDecoratorSize, LinkDecorator.DecoratorEmptyArrow, DefaultDecoratorSize, true);

break;

case BidirectionalAssociation _ when base.DecoratorTo != null:
SetDecorators(null, DefaultDecoratorSize, null, DefaultDecoratorSize, true);

break;
}
}

return base.DecoratorTo;
Expand Down
Loading

0 comments on commit 8b12b5e

Please sign in to comment.