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

Commit

Permalink
Added SourceAutoProperty and TargetAutoProperty with tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
msawczyn committed Aug 28, 2020
1 parent 2e4b5b4 commit 71eff55
Show file tree
Hide file tree
Showing 22 changed files with 2,082 additions and 305 deletions.
Binary file modified dist/Sawczyn.EFDesigner.EFModel.DslPackage.vsix
Binary file not shown.
12 changes: 6 additions & 6 deletions docs/Gemfile.lock
Expand Up @@ -27,7 +27,7 @@ GEM
github-pages (179)
activesupport (= 4.2.9)
github-pages-health-check (= 1.4.0)
jekyll (= 3.6.2)
jekyll (= 3.6.3)
jekyll-avatar (= 0.5.0)
jekyll-coffeescript (= 1.1.1)
jekyll-commonmark-ghpages (= 0.1.5)
Expand Down Expand Up @@ -61,7 +61,7 @@ GEM
jekyll-theme-time-machine (= 0.1.0)
jekyll-titles-from-headings (= 0.5.1)
jemoji (= 0.9.0)
kramdown (= 1.16.2)
kramdown (>= 2.3.0)
liquid (= 4.0.0)
listen (= 3.1.5)
mercenary (~> 0.3)
Expand All @@ -80,12 +80,12 @@ GEM
nokogiri (>= 1.4)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
jekyll (3.6.2)
jekyll (3.6.3)
addressable (~> 2.4)
colorator (~> 1.0)
jekyll-sass-converter (~> 1.0)
jekyll-watch (~> 1.1)
kramdown (~> 1.14)
kramdown (>= 2.3.0)
liquid (~> 4.0)
mercenary (~> 0.3.3)
pathutil (~> 0.9)
Expand All @@ -98,7 +98,7 @@ GEM
coffee-script-source (~> 1.11.1)
jekyll-commonmark (1.1.0)
commonmarker (~> 0.14)
jekyll (>= 3.0, < 4.0)
jekyll (>= 3.63, < 3.7)
jekyll-commonmark-ghpages (0.1.5)
commonmarker (~> 0.17.6)
jekyll-commonmark (~> 1)
Expand Down Expand Up @@ -185,7 +185,7 @@ GEM
gemoji (~> 3.0)
html-pipeline (~> 2.2)
jekyll (~> 3.0)
kramdown (1.16.2)
kramdown (>= 2.3.0)
liquid (4.0.0)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
Expand Down

Large diffs are not rendered by default.

93 changes: 93 additions & 0 deletions src/Dsl/CustomCode/Partials/Association.cs
Expand Up @@ -424,6 +424,97 @@ internal void ResetValue(Association element)

#endregion CollectionClass tracking property

#region TargetAutoProperty tracking property

private bool targetAutoPropertyStorage;

private bool GetTargetAutoPropertyValue()
{
if (!this.IsLoading() && IsTargetAutoPropertyTracking)
{
try
{
return Source?.AutoPropertyDefault ?? true;
}
catch (NullReferenceException)
{
return default;
}
catch (Exception e)
{
if (CriticalException.IsCriticalException(e))
throw;

return default;
}
}

return targetAutoPropertyStorage;
}

private void SetTargetAutoPropertyValue(bool value)
{
targetAutoPropertyStorage = value;

if (!Store.InUndoRedoOrRollback && !this.IsLoading())
IsTargetAutoPropertyTracking = (value == Source.AutoPropertyDefault);
}

internal sealed partial class IsTargetAutoPropertyTrackingPropertyHandler
{
/// <summary>
/// Called after the IsTargetAutoPropertyTracking property changes.
/// </summary>
/// <param name="element">The model element that has the property that changed. </param>
/// <param name="oldValue">The previous value of the property. </param>
/// <param name="newValue">The new value of the property. </param>
protected override void OnValueChanged(Association element, bool oldValue, bool newValue)
{
base.OnValueChanged(element, oldValue, newValue);
if (!element.Store.InUndoRedoOrRollback && newValue)
{
DomainPropertyInfo propInfo = element.Store.DomainDataDirectory.GetDomainProperty(TargetAutoPropertyDomainPropertyId);
propInfo.NotifyValueChange(element);
}
}

/// <summary>Performs the reset operation for the IsTargetAutoPropertyTracking property for a model element.</summary>
/// <param name="element">The model element that has the property to reset.</param>
internal void ResetValue(Association element)
{
object calculatedValue = null;
try
{
calculatedValue = element.Source?.AutoPropertyDefault;
}
catch (NullReferenceException) { }
catch (Exception e)
{
if (CriticalException.IsCriticalException(e))
throw;
}

if (calculatedValue != null && element.TargetAutoProperty == (bool)calculatedValue)
element.isTargetAutoPropertyTrackingPropertyStorage = true;
}

/// <summary>
/// Method to set IsTargetAutoPropertyTracking to false so that this instance of this tracking property is not
/// storage-based.
/// </summary>
/// <param name="element">
/// The element on which to reset the property
/// value.
/// </param>
internal void PreResetValue(Association element) =>
// Force the IsTargetAutoPropertyTracking property to false so that the value
// of the TargetAutoProperty property is retrieved from storage.
element.isTargetAutoPropertyTrackingPropertyStorage = false;
}

#endregion TargetAutoProperty tracking property


/// <summary>
/// Calls the pre-reset method on the associated property value handler for each
/// tracking property of this model element.
Expand All @@ -433,6 +524,7 @@ internal virtual void PreResetIsTrackingProperties()
{
IsCollectionClassTrackingPropertyHandler.Instance.PreResetValue(this);
IsTargetImplementNotifyTrackingPropertyHandler.Instance.PreResetValue(this);
IsTargetAutoPropertyTrackingPropertyHandler.Instance.PreResetValue(this);
// same with other tracking properties as they get added
}

Expand All @@ -445,6 +537,7 @@ internal virtual void ResetIsTrackingProperties()
{
IsCollectionClassTrackingPropertyHandler.Instance.ResetValue(this);
IsTargetImplementNotifyTrackingPropertyHandler.Instance.ResetValue(this);
IsTargetAutoPropertyTrackingPropertyHandler.Instance.ResetValue(this);
// same with other tracking properties as they get added
}

Expand Down
92 changes: 92 additions & 0 deletions src/Dsl/CustomCode/Partials/BidirectionalAssociation.cs
Expand Up @@ -135,6 +135,96 @@ internal void PreResetValue(BidirectionalAssociation element)

#endregion

#region SourceAutoProperty tracking property

private bool sourceAutoPropertyStorage;

private bool GetSourceAutoPropertyValue()
{
if (!this.IsLoading() && IsSourceAutoPropertyTracking)
{
try
{
return Source?.AutoPropertyDefault ?? true;
}
catch (NullReferenceException)
{
return default;
}
catch (Exception e)
{
if (CriticalException.IsCriticalException(e))
throw;

return default;
}
}

return sourceAutoPropertyStorage;
}

private void SetSourceAutoPropertyValue(bool value)
{
sourceAutoPropertyStorage = value;

if (!Store.InUndoRedoOrRollback && !this.IsLoading())
IsSourceAutoPropertyTracking = (value == Source.AutoPropertyDefault);
}

internal sealed partial class IsSourceAutoPropertyTrackingPropertyHandler
{
/// <summary>
/// Called after the IsSourceAutoPropertyTracking property changes.
/// </summary>
/// <param name="element">The model element that has the property that changed. </param>
/// <param name="oldValue">The previous value of the property. </param>
/// <param name="newValue">The new value of the property. </param>
protected override void OnValueChanged(BidirectionalAssociation element, bool oldValue, bool newValue)
{
base.OnValueChanged(element, oldValue, newValue);
if (!element.Store.InUndoRedoOrRollback && newValue)
{
DomainPropertyInfo propInfo = element.Store.DomainDataDirectory.GetDomainProperty(SourceAutoPropertyDomainPropertyId);
propInfo.NotifyValueChange(element);
}
}

/// <summary>Performs the reset operation for the IsSourceAutoPropertyTracking property for a model element.</summary>
/// <param name="element">The model element that has the property to reset.</param>
internal void ResetValue(BidirectionalAssociation element)
{
object calculatedValue = null;
try
{
calculatedValue = element.Source?.AutoPropertyDefault;
}
catch (NullReferenceException) { }
catch (Exception e)
{
if (CriticalException.IsCriticalException(e))
throw;
}

if (calculatedValue != null && element.Source.AutoPropertyDefault == (bool)calculatedValue)
element.isSourceAutoPropertyTrackingPropertyStorage = true;
}

/// <summary>
/// Method to set IsSourceAutoPropertyTracking to false so that this instance of this tracking property is not
/// storage-based.
/// </summary>
/// <param name="element">
/// The element on which to reset the property
/// value.
/// </param>
internal void PreResetValue(BidirectionalAssociation element) =>
// Force the IsSourceAutoPropertyTracking property to false so that the value
// of the SourceAutoProperty property is retrieved from storage.
element.isSourceAutoPropertyTrackingPropertyStorage = false;
}

#endregion SourceAutoProperty tracking property

/// <summary>
/// Calls the pre-reset method on the associated property value handler for each
/// tracking property of this model element.
Expand All @@ -144,6 +234,7 @@ internal override void PreResetIsTrackingProperties()
{
base.PreResetIsTrackingProperties();
IsSourceImplementNotifyTrackingPropertyHandler.Instance.PreResetValue(this);
IsSourceAutoPropertyTrackingPropertyHandler.Instance.PreResetValue(this);
// same with other tracking properties as they get added
}

Expand All @@ -156,6 +247,7 @@ internal override void ResetIsTrackingProperties()
{
base.ResetIsTrackingProperties();
IsSourceImplementNotifyTrackingPropertyHandler.Instance.ResetValue(this);
IsSourceAutoPropertyTrackingPropertyHandler.Instance.ResetValue(this);
// same with other tracking properties as they get added
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/Dsl/CustomCode/Partials/ModelClass.cs
Expand Up @@ -279,7 +279,6 @@ public virtual void PreResetIsTrackingProperties()
IsDatabaseSchemaTrackingPropertyHandler.Instance.PreResetValue(this);
IsNamespaceTrackingPropertyHandler.Instance.PreResetValue(this);
IsOutputDirectoryTrackingPropertyHandler.Instance.PreResetValue(this);

// same with other tracking properties as they get added
}

Expand Down Expand Up @@ -861,6 +860,14 @@ protected virtual void OnAutoPropertyDefaultChanged(bool oldValue, bool newValue
Attributes,
ModelAttribute.AutoPropertyDomainPropertyId,
ModelAttribute.IsAutoPropertyTrackingDomainPropertyId);
TrackingHelper.UpdateTrackingCollectionProperty(Store,
Store.GetAll<Association>().Where(a => a.Source?.FullName == FullName),
Association.TargetAutoPropertyDomainPropertyId,
Association.IsTargetAutoPropertyTrackingDomainPropertyId);
TrackingHelper.UpdateTrackingCollectionProperty(Store,
Store.GetAll<BidirectionalAssociation>().Where(a => a.Target?.FullName == FullName),
BidirectionalAssociation.SourceAutoPropertyDomainPropertyId,
BidirectionalAssociation.IsSourceAutoPropertyTrackingDomainPropertyId);
}

internal sealed partial class AutoPropertyDefaultPropertyHandler
Expand Down
39 changes: 34 additions & 5 deletions src/Dsl/CustomCode/Type Descriptors/AssociationTypeDescriptor.cs
Expand Up @@ -25,7 +25,7 @@ private PropertyDescriptorCollection GetCustomProperties(Attribute[] attributes)
{
storeDomainDataDirectory = association.Store.DomainDataDirectory;
BidirectionalAssociation bidirectionalAssociation = association as BidirectionalAssociation;

EFCoreValidator.AdjustEFCoreProperties(propertyDescriptors, association);

// show FKPropertyName only when possible and required
Expand Down Expand Up @@ -58,18 +58,18 @@ private PropertyDescriptorCollection GetCustomProperties(Attribute[] attributes)
if (association.SourceMultiplicity != Multiplicity.ZeroMany || association.TargetMultiplicity != Multiplicity.ZeroMany)
propertyDescriptors.Remove("JoinTableName");

// only show backing field and property access mode for EFCore5+ non-collection associations
if (!association.Source.ModelRoot.IsEFCore5Plus || association.TargetMultiplicity == Multiplicity.ZeroMany)
// only show backing field name and property access mode if not an autoproperty
if (association.TargetAutoProperty)
{
propertyDescriptors.Remove("TargetBackingFieldName");
propertyDescriptors.Remove("TargetPropertyAccessMode");
}

if (!association.Source.ModelRoot.IsEFCore5Plus || bidirectionalAssociation?.SourceMultiplicity == Multiplicity.ZeroMany)
if (bidirectionalAssociation?.SourceAutoProperty != false)
{
propertyDescriptors.Remove("SourceBackingFieldName");
propertyDescriptors.Remove("SourcePropertyAccessMode");
}

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

//Add the descriptors for the tracking properties
Expand All @@ -96,6 +96,20 @@ private PropertyDescriptorCollection GetCustomProperties(Attribute[] attributes)
+ "Only valid for non-collection targets.")
, new CategoryAttribute("End 2")
}));

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

if (bidirectionalAssociation?.SourceMultiplicity == Multiplicity.One || bidirectionalAssociation?.SourceMultiplicity == Multiplicity.ZeroOne)
Expand All @@ -110,6 +124,21 @@ private PropertyDescriptorCollection GetCustomProperties(Attribute[] attributes)
+ "Only valid for non-collection targets.")
, new CategoryAttribute("End 1")
}));

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

}

}
Expand Down

0 comments on commit 71eff55

Please sign in to comment.