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

Commit

Permalink
Properties with backing fields (i.e., not auto-properties) can now ch…
Browse files Browse the repository at this point in the history
…oose how EF will read/write those values (still need to work the T4 ouput)
  • Loading branch information
msawczyn committed Aug 24, 2020
1 parent 059ffff commit f6a9b85
Show file tree
Hide file tree
Showing 48 changed files with 1,974 additions and 575 deletions.
44 changes: 44 additions & 0 deletions UpdateVersion.ps1
@@ -0,0 +1,44 @@
$xml = (get-content src\Dsl\DslDefinition.dsl -Raw)

$major = 0
$minor = 0
$build = 0
$revision = 0

$m = $xml | Select-String -Pattern 'MajorVersion="(\d+)"'
if ($m.Matches.Success) { $major = $m.Matches.Groups[1].Value }
$m = $xml | Select-String -Pattern 'MinorVersion="(\d+)"'
if ($m.Matches.Success) { $minor = $m.Matches.Groups[1].Value }
$m = $xml | Select-String -Pattern 'Build="(\d+)"'
if ($m.Matches.Success) { $build = $m.Matches.Groups[1].Value }
$m = $xml | Select-String -Pattern 'Revision="(\d+)"'
if ($m.Matches.Success) { $revision = $m.Matches.Groups[1].Value }

$version = $major+'.'+$minor+'.'+$build+'.'+$revision

$assemblyInfo =
'src\Dsl\Properties\AssemblyInfo.cs',
'src\DslPackage\Properties\AssemblyInfo.cs',
'src\Utilities\ParsingModels\AssemblyInfo.cs'

foreach ($f in $assemblyInfo) {
[regex]::Replace((get-content $f -Raw), '\[assembly:\s*AssemblyVersion\("[\d\.]+"\)\]', '[assembly: AssemblyVersion("'+$version+'")]') | set-content $f
[regex]::Replace((get-content $f -Raw), '\[assembly:\s*AssemblyFileVersion\("[\d\.]+"\)\]', '[assembly: AssemblyFileVersion("'+$version+'")]') | set-content $f
}

$t4 =
'src\DslPackage\TextTemplates\EF6Designer.ttinclude',
'src\DslPackage\TextTemplates\EFCoreDesigner.ttinclude',
'src\DslPackage\TextTemplates\EFDesigner.ttinclude',
'src\DslPackage\TextTemplates\MultipleOutputHelper.ttinclude',
'src\DslPackage\TextTemplates\VSIntegration.ttinclude',
'src\DslPackage\TextTemplates\EditingOnly\EF6Designer.cs',
'src\DslPackage\TextTemplates\EditingOnly\EFCoreDesigner.cs',
'src\DslPackage\TextTemplates\EditingOnly\EFDesigner.cs',
'src\DslPackage\TextTemplates\EditingOnly\MultipleOutputHelper.cs',
'src\DslPackage\TextTemplates\EditingOnly\VSIntegration.cs'

foreach ($f in $t4) {
[regex]::Replace((get-content $f -Raw), '(\s*)// EFDesigner v[\d\.]+', '$1// EFDesigner v'+$version) | set-content $f
}

14 changes: 9 additions & 5 deletions changelog.txt
@@ -1,10 +1,14 @@
2.0.5.4
2.1.0
- 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
- Added IPAddress to the list of property types for EFCore5.x
- Added ability to specify both default database collation and a collation override at the property level for EFCore5.x
- Added ModelRoot.IsEFCore5Plus convenience property; can be used in custom T4 edits
- Can now customize backing field names for non-AutoProperty properties in preparation for EFCore5.x persistent fields
- Changes for EFCore5.X (available when selecting EFCore output with version >= 5)
- Added IPAddress to the list of property types
- Added ability to specify both default database collation and a collation override at the property level
- Added ModelRoot.IsEFCore5Plus convenience property. It can be used in custom T4 edits
- Many-to-many 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., not auto-properties) can now choose how EF will read/write those values (see https://docs.microsoft.com/en-us/ef/core/modeling/backing-field).

2.0.5.3
- Provide option to save diagrams as uncompressed XML to facilitate version control (in Tools/Options/Entity Framework Visual Editor)
Expand Down
99 changes: 96 additions & 3 deletions src/Dsl/CustomCode/Partials/ModelAttribute.cs
Expand Up @@ -90,7 +90,7 @@ public bool SupportsInitialValue
case "MultiPoint":
case "MultiPolygon":
case "Point":
case "Polygon":
case "Polygon":
return false;
}

Expand Down Expand Up @@ -387,7 +387,7 @@ internal void SetFKMods(Association association, string summaryBoilerplate = nul
RedrawItem();
}

#region ColumnName
#region ColumnName

/// <summary>Storage for the ColumnName property.</summary>
private string columnNameStorage;
Expand Down Expand Up @@ -475,6 +475,42 @@ public void SetImplementNotifyValue(bool value)

#endregion

#region DatabaseCollation

private string databaseCollation;

public string GetDatabaseCollationValue()
{
if (!this.IsLoading() && IsAutoPropertyTracking)
{
try
{
return ModelClass?.ModelRoot?.DatabaseCollationDefault ?? "default";
}
catch (Exception e)
{
if (CriticalException.IsCriticalException(e))
throw;

return "default";
}
}

return databaseCollation;

}

public void SetDatabaseCollationValue(string value)
{
databaseCollation = value;

if (!Store.InUndoRedoOrRollback && !this.IsLoading())
IsDatabaseCollationTracking = (databaseCollation == (ModelClass?.ModelRoot?.DatabaseCollationDefault ?? "default"));

}

#endregion

#region AutoProperty

/// <summary>Storage for the AutoProperty property.</summary>
Expand Down Expand Up @@ -564,6 +600,60 @@ public void SetColumnTypeValue(string value)

#region Tracking Properties

internal sealed partial class IsDatabaseCollationTrackingPropertyHandler
{
/// <summary>
/// Called after the IsDatabaseCollationTracking 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(ModelAttribute element, bool oldValue, bool newValue)
{
base.OnValueChanged(element, oldValue, newValue);
if (!element.Store.InUndoRedoOrRollback && newValue)
{
DomainPropertyInfo propInfo = element.Store.DomainDataDirectory.GetDomainProperty(DatabaseCollationDomainPropertyId);
propInfo.NotifyValueChange(element);
}
}

/// <summary>Performs the reset operation for the IsDatabaseCollationTracking property for a model element.</summary>
/// <param name="element">The model element that has the property to reset.</param>
internal void ResetValue(ModelAttribute element)
{
string calculatedValue = null;

try
{
calculatedValue = "default";
}
catch (NullReferenceException) { }
catch (Exception e)
{
if (CriticalException.IsCriticalException(e))
throw;
}

if (calculatedValue != null && element.DatabaseCollation == calculatedValue)
element.isDatabaseCollationTrackingPropertyStorage = true;
}

/// <summary>
/// Method to set IsDatabaseCollationTracking 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(ModelAttribute element)
{
// Force the IsDatabaseCollationTracking property to false so that the value
// of the DatabaseCollation property is retrieved from storage.
element.isDatabaseCollationTrackingPropertyStorage = false;
}
}

internal sealed partial class IsColumnNameTrackingPropertyHandler
{
/// <summary>
Expand Down Expand Up @@ -791,6 +881,7 @@ internal virtual void PreResetIsTrackingProperties()
IsColumnTypeTrackingPropertyHandler.Instance.PreResetValue(this);
IsImplementNotifyTrackingPropertyHandler.Instance.PreResetValue(this);
IsAutoPropertyTrackingPropertyHandler.Instance.PreResetValue(this);
IsDatabaseCollationTrackingPropertyHandler.Instance.PreResetValue(this);
// same with other tracking properties as they get added
}

Expand All @@ -805,6 +896,7 @@ internal virtual void ResetIsTrackingProperties()
IsColumnTypeTrackingPropertyHandler.Instance.ResetValue(this);
IsImplementNotifyTrackingPropertyHandler.Instance.ResetValue(this);
IsAutoPropertyTrackingPropertyHandler.Instance.ResetValue(this);
IsDatabaseCollationTrackingPropertyHandler.Instance.ResetValue(this);
// same with other tracking properties as they get added
}

Expand All @@ -831,7 +923,8 @@ private void GeographyTypeDoesNotMatchEFVersion(ValidationContext context)

if (ModelClass.ModelRoot.EntityFrameworkVersion == EFVersion.EFCore)
{
if (Type.StartsWith("Geography")) {
if (Type.StartsWith("Geography"))
{
context.LogError($"{ModelClass.Name}.{Name}: Geography type invalid for EF Core. Use Geometry instead.", "AEInvalidGeography", this);
hasWarning = true;
RedrawItem();
Expand Down
33 changes: 28 additions & 5 deletions src/Dsl/CustomCode/Partials/ModelRoot.cs
Expand Up @@ -15,7 +15,7 @@
namespace Sawczyn.EFDesigner.EFModel
{
[ValidationState(ValidationState.Enabled)]
public partial class ModelRoot: IHasStore
public partial class ModelRoot : IHasStore
{
public static readonly PluralizationService PluralizationService;

Expand Down Expand Up @@ -99,7 +99,7 @@ public string[] SpatialTypes
{
get
{
return EntityFrameworkVersion == EFVersion.EF6
return EntityFrameworkVersion == EFVersion.EF6
? new[]
{
"Geography"
Expand Down Expand Up @@ -177,7 +177,7 @@ public string[] ValidCLRTypes
{
get
{
List<string> validClrTypes = new List<string>(new []
List<string> validClrTypes = new List<string>(new[]
{
"Binary",
"Boolean", "Boolean?", "Nullable<Boolean>",
Expand All @@ -189,11 +189,11 @@ public string[] ValidCLRTypes
"Decimal", "Decimal?", "Nullable<Decimal>",
"Double", "Double?", "Nullable<Double>",
"Guid", "Guid?", "Nullable<Guid>"
});
});
if (IsEFCore5Plus)
validClrTypes.Add("System.Net.IPAddress");

validClrTypes.AddRange(new []
validClrTypes.AddRange(new[]
{
"Int16", "Int16?", "Nullable<Int16>",
"Int32", "Int32?", "Nullable<Int32>",
Expand Down Expand Up @@ -344,6 +344,29 @@ protected override void OnValueChanged(ModelRoot element, string oldValue, strin

#endregion DatabaseSchema tracking property

#region DatabaseCollationDefault tracking property

protected virtual void OnDatabaseCollationDefaultChanged(string oldValue, string newValue)
{
TrackingHelper.UpdateTrackingCollectionProperty(Store,
Classes,
ModelAttribute.DatabaseCollationDomainPropertyId,
ModelAttribute.IsDatabaseCollationTrackingDomainPropertyId);
}

internal sealed partial class DatabaseCollationDefaultPropertyHandler
{
protected override void OnValueChanged(ModelRoot element, string oldValue, string newValue)
{
base.OnValueChanged(element, oldValue, newValue);

if (!element.Store.InUndoRedoOrRollback)
element.OnDatabaseCollationDefaultChanged(oldValue, newValue);
}
}

#endregion DatabaseCollationDefault tracking property

#region DefaultCollectionClass tracking property

protected virtual void OnCollectionClassChanged(string oldValue, string newValue)
Expand Down
Expand Up @@ -32,7 +32,7 @@ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContex
ModelRoot modelRoot = store.ModelRoot();

// if this is an identity property, there's a limited range of possibilities if EF6 or EFCore before v5
bool useIdentityTypes = (context.Instance as ModelAttribute)?.IsIdentity == true && !modelRoot.IsEFCore5Plus)
bool useIdentityTypes = (context.Instance as ModelAttribute)?.IsIdentity == true && !modelRoot.IsEFCore5Plus;

List<string> values = new List<string>();

Expand Down
Expand Up @@ -61,9 +61,12 @@ private PropertyDescriptorCollection GetCustomProperties(Attribute[] attributes)
if (!modelAttribute.Indexed)
propertyDescriptors.Remove("IndexedUnique");

// don't display BackingField unless AutoProperty is false
if (modelAttribute.AutoProperty)
// don't display BackingField or PropertyAccessMode unless AutoProperty is false
if (modelAttribute.AutoProperty)
{
propertyDescriptors.Remove("BackingFieldName");
propertyDescriptors.Remove("PropertyAccessMode");
}

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

Expand Down Expand Up @@ -108,6 +111,16 @@ private PropertyDescriptorCollection GetCustomProperties(Attribute[] attributes)
, new DescriptionAttribute("Should this attribute implement INotifyPropertyChanged?")
, new CategoryAttribute("Code Generation")
}));

propertyDescriptors.Add(new TrackingPropertyDescriptor(modelAttribute
, storeDomainDataDirectory.GetDomainProperty(ModelAttribute.DatabaseCollationDomainPropertyId)
, storeDomainDataDirectory.GetDomainProperty(ModelAttribute.IsDatabaseCollationTrackingDomainPropertyId)
, new Attribute[]
{
new DisplayNameAttribute("Database Collation")
, new DescriptionAttribute("Overrides the default database collation setting for the column that persists this attribute")
, new CategoryAttribute("Database")
}));
}

// Return the property descriptors for this element
Expand Down
2 changes: 1 addition & 1 deletion src/Dsl/CustomCode/Utilities/Nuget/NuGetHelper.cs
Expand Up @@ -10,7 +10,7 @@ public class NuGetHelper
public const string PACKAGEID_EF6 = "EntityFramework";
public const string PACKAGEID_EFCORE = "Microsoft.EntityFrameworkCore";

private const string NUGET_URL = "https://api-v2v3search-0.nuget.org/query?q={0}&prerelease=false";
private const string NUGET_URL = "https://api-v2v3search-0.nuget.org/query?q={0}&prerelease=true";
private static readonly HttpClient httpClient = new HttpClient();

static NuGetHelper()
Expand Down

0 comments on commit f6a9b85

Please sign in to comment.