Skip to content

Commit 904ebe7

Browse files
authored
Moved IsManyToManyJoinEntityType extension class (#241)
* #240 Moved IsManyToManyJoinEntityType extension class. Use IsManyToManyJoinEntityType to prevent InverseProperty and ForeignKey Annotations from being generated in Virtual Tables. * Added functionality for Enum Defaults and Enums in ManyToMany virtual tables. * Added functionality for Enum Defaults and Enums in ManyToMany virtual tables. #242
1 parent b88633f commit 904ebe7

File tree

8 files changed

+165
-35
lines changed

8 files changed

+165
-35
lines changed

src/EntityFrameworkCore.Scaffolding.Handlebars/CodeTemplates/CSharpEntityType/Partials/Properties.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
{{#each property-annotations}}
99
{{{property-annotation}}}
1010
{{/each}}
11-
public {{property-type}} {{property-name}} { get; set; }{{#if nullable-reference-types }}{{#unless property-isnullable}} = null!;{{/unless}}{{/if}}
11+
public {{property-type}} {{property-name}} { get; set; }{{#if nullable-reference-types }}{{#unless property-isnullable}} = null!;{{/unless}}{{else}}{{#if property-default-enum}} = {{property-default-enum}};{{/if}}{{/if}}
1212
{{/each}}
1313
{{#if nav-properties}}
1414

src/EntityFrameworkCore.Scaffolding.Handlebars/EntityPropertyInfo.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@ public EntityPropertyInfo() { }
1616
/// <param name="propertyType">Property type.</param>
1717
/// <param name="propertyName">Property name.</param>
1818
/// <param name="propertyIsNullable">Property is nullable.</param>
19-
public EntityPropertyInfo(string propertyType, string propertyName, bool? propertyIsNullable = null)
19+
/// <param name="isEnumPropertyType">Is Enumeration Property Type</param>
20+
/// <param name="propertyDefaultEnumValue">Default Enumeration Value. Format will be EnumName.EnumValue</param>
21+
public EntityPropertyInfo(string propertyType, string propertyName, bool? propertyIsNullable = null
22+
, bool? isEnumPropertyType = false, string propertyDefaultEnumValue = null)
2023
{
2124
PropertyType = propertyType;
2225
PropertyName = propertyName;
2326
PropertyIsNullable = propertyIsNullable;
27+
IsEnumPropertyType = isEnumPropertyType;
28+
PropertyDefaultEnumValue = propertyDefaultEnumValue;
2429
}
2530

2631
/// <summary>
@@ -37,5 +42,16 @@ public EntityPropertyInfo(string propertyType, string propertyName, bool? proper
3742
/// Property is nullable.
3843
/// </summary>
3944
public bool? PropertyIsNullable { get; set; }
45+
/// <summary>
46+
/// Property Type is an Enumeration.
47+
/// Used in TransformPropertyTypeIfEnumaration
48+
/// for Many to Many Virtual EntityTypes
49+
/// </summary>
50+
public bool? IsEnumPropertyType { get; set; }
51+
/// <summary>
52+
/// Property Default Value when using Enumarations
53+
/// Format will be EnumName.EnumValue
54+
/// </summary>
55+
public string PropertyDefaultEnumValue { get; set; }
4056
}
4157
}

src/EntityFrameworkCore.Scaffolding.Handlebars/HbsCSharpDbContextGenerator.cs

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ protected virtual void GenerateOnModelCreating([NotNull] IModel model)
244244

245245
foreach (var entityType in model.GetScaffoldEntityTypes(_options.Value))
246246
{
247-
if (IsManyToManyJoinEntityType(entityType))
247+
if (entityType.IsManyToManyJoinEntityType())
248248
{
249249
continue;
250250
}
@@ -285,7 +285,7 @@ private void GenerateDbSets(IModel model)
285285

286286
foreach (var entityType in model.GetScaffoldEntityTypes(_options.Value))
287287
{
288-
if (IsManyToManyJoinEntityType(entityType))
288+
if (entityType.IsManyToManyJoinEntityType())
289289
{
290290
continue;
291291
}
@@ -683,8 +683,18 @@ private void GenerateProperty(IEntityType entityType, IProperty property, bool u
683683
}
684684
else if (defaultValue != null)
685685
{
686-
lines.Add(
687-
$".{nameof(RelationalPropertyBuilderExtensions.HasDefaultValue)}({CSharpHelper.UnknownLiteral(defaultValue)})");
686+
// Lookup Default Enum Value
687+
var defaultEnumValue = EntityTypeTransformationService.TransformPropertyDefaultEnum(entityType, property.Name, property.DeclaringType.Name);
688+
if (string.IsNullOrEmpty(defaultEnumValue))
689+
{
690+
lines.Add(
691+
$".{nameof(RelationalPropertyBuilderExtensions.HasDefaultValue)}({CSharpHelper.UnknownLiteral(defaultValue)})");
692+
}
693+
else
694+
{
695+
lines.Add(
696+
$".{nameof(RelationalPropertyBuilderExtensions.HasDefaultValue)}({defaultEnumValue})");
697+
}
688698
annotations.Remove(RelationalAnnotationNames.DefaultValue);
689699
annotations.Remove(RelationalAnnotationNames.DefaultValueSql);
690700
}
@@ -912,8 +922,18 @@ private void GenerateManyToMany(ISkipNavigation skipNavigation, IndentedStringBu
912922

913923
foreach (var property in joinEntityType.GetProperties())
914924
{
915-
lines.Add(
916-
$"j.{nameof(EntityTypeBuilder.IndexerProperty)}<{CSharpHelper.Reference(property.ClrType)}>({CSharpHelper.Literal(property.Name)})");
925+
// Lookup Property Type Transformation if it is an Enumeration
926+
string enumPropertyType = EntityTypeTransformationService.TransformPropertyTypeIfEnumaration(joinEntityType, property.Name, property.DeclaringType.Name);
927+
if (enumPropertyType == null)
928+
{
929+
lines.Add(
930+
$"j.{nameof(EntityTypeBuilder.IndexerProperty)}<{CSharpHelper.Reference(property.ClrType)}>({CSharpHelper.Literal(property.Name)})");
931+
}
932+
else
933+
{
934+
lines.Add(
935+
$"j.{nameof(EntityTypeBuilder.IndexerProperty)}<{enumPropertyType}>({CSharpHelper.Literal(property.Name)})");
936+
}
917937

918938
var propertyAnnotations = AnnotationCodeGenerator
919939
.FilterIgnoredAnnotations(property.GetAnnotations())
@@ -969,12 +989,14 @@ private void GenerateManyToMany(ISkipNavigation skipNavigation, IndentedStringBu
969989
{
970990
lines.Add($".{nameof(RelationalPropertyBuilderExtensions.HasDefaultValue)}()");
971991
propertyAnnotations.Remove(RelationalAnnotationNames.DefaultValue);
992+
propertyAnnotations.Remove(RelationalAnnotationNames.DefaultValueSql);
972993
}
973994
else if (defaultValue != null)
974995
{
975996
lines.Add(
976997
$".{nameof(RelationalPropertyBuilderExtensions.HasDefaultValue)}({CSharpHelper.UnknownLiteral(defaultValue)})");
977998
propertyAnnotations.Remove(RelationalAnnotationNames.DefaultValue);
999+
propertyAnnotations.Remove(RelationalAnnotationNames.DefaultValueSql);
9781000
}
9791001
}
9801002

@@ -1204,30 +1226,5 @@ private string GenerateAnnotation(IAnnotation annotation)
12041226
=> $".HasAnnotation({CSharpHelper.Literal(annotation.Name)}, " +
12051227
$"{CSharpHelper.UnknownLiteral(annotation.Value)})";
12061228

1207-
private static bool IsManyToManyJoinEntityType(IEntityType entityType)
1208-
{
1209-
if (!entityType.GetNavigations().Any()
1210-
&& !entityType.GetSkipNavigations().Any())
1211-
{
1212-
var primaryKey = entityType.FindPrimaryKey();
1213-
var properties = entityType.GetProperties().ToList();
1214-
var foreignKeys = entityType.GetForeignKeys().ToList();
1215-
if (primaryKey != null
1216-
&& primaryKey.Properties.Count > 1
1217-
&& foreignKeys.Count == 2
1218-
&& primaryKey.Properties.Count == properties.Count
1219-
&& foreignKeys[0].Properties.Count + foreignKeys[1].Properties.Count == properties.Count
1220-
&& !foreignKeys[0].Properties.Intersect(foreignKeys[1].Properties).Any()
1221-
&& foreignKeys[0].IsRequired
1222-
&& foreignKeys[1].IsRequired
1223-
&& !foreignKeys[0].IsUnique
1224-
&& !foreignKeys[1].IsUnique)
1225-
{
1226-
return true;
1227-
}
1228-
}
1229-
1230-
return false;
1231-
}
12321229
}
12331230
}

src/EntityFrameworkCore.Scaffolding.Handlebars/HbsCSharpEntityTypeGenerator.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ protected virtual void GenerateProperties(IEntityType entityType)
266266
{ "property-annotations", PropertyAnnotationsData },
267267
{ "property-comment", _options?.Value?.GenerateComments == true ? GenerateComment(property.GetComment(), 2) : null },
268268
{ "property-isnullable", propertyIsNullable },
269+
{ "property-isenum", false },
270+
{ "property-default-enum", null },
269271
{ "nullable-reference-types", UseNullableReferenceTypes }
270272
});
271273
}
@@ -635,6 +637,11 @@ private void GenerateNavigationDataAnnotations(IEntityType entityType, INavigati
635637
{
636638
if (navigation == null) throw new ArgumentNullException(nameof(navigation));
637639

640+
if (navigation.ForeignKey.DeclaringEntityType.IsManyToManyJoinEntityType())
641+
{
642+
return;
643+
}
644+
638645
GenerateForeignKeyAttribute(entityType, navigation);
639646
GenerateInversePropertyAttribute(entityType, navigation);
640647
}
@@ -697,6 +704,11 @@ private void GenerateNavigationDataAnnotations(IEntityType entityType, ISkipNavi
697704
{
698705
if (navigation == null) throw new ArgumentNullException(nameof(navigation));
699706

707+
if (navigation.ForeignKey.DeclaringEntityType.IsManyToManyJoinEntityType())
708+
{
709+
return;
710+
}
711+
700712
GenerateForeignKeyAttribute(entityType, navigation);
701713
GenerateInversePropertyAttribute(entityType, navigation);
702714
}

src/EntityFrameworkCore.Scaffolding.Handlebars/HbsEntityTypeTransformationServiceBase.cs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace EntityFrameworkCore.Scaffolding.Handlebars
77
/// Default service for transforming entity type definitions.
88
/// </summary>
99
public abstract class HbsEntityTypeTransformationServiceBase : IEntityTypeTransformationService
10-
{
10+
{
1111
/// <summary>
1212
/// Entity name transformer.
1313
/// </summary>
@@ -95,6 +95,48 @@ public string TransformPropertyName(IEntityType entityType, string propertyName,
9595
return propertyName;
9696
}
9797

98+
/// <summary>
99+
/// Transforms the Property Type if it is an Enumeration.
100+
/// Returns null when not an Enumeration
101+
/// </summary>
102+
/// <param name="entityType">Entity type.</param>
103+
/// <param name="propertyName">Property name.</param>
104+
/// <param name="propertyType">Property type</param>
105+
/// <returns>Transformed property name, null when not an Enumeration</returns>
106+
public string TransformPropertyTypeIfEnumaration(IEntityType entityType, string propertyName, string propertyType)
107+
{
108+
var propTypeInfo = new EntityPropertyInfo { PropertyName = propertyName, PropertyType = propertyType };
109+
if (PropertyTransformer2 != null)
110+
{
111+
EntityPropertyInfo epi = PropertyTransformer2?.Invoke(entityType, propTypeInfo);
112+
return epi.IsEnumPropertyType == true ? epi.PropertyType : null;
113+
}
114+
else if (PropertyTransformer != null)
115+
{
116+
EntityPropertyInfo epi = PropertyTransformer?.Invoke(propTypeInfo);
117+
return epi.IsEnumPropertyType == true ? epi.PropertyType : null;
118+
}
119+
return null;
120+
}
121+
122+
/// <summary>
123+
/// Transform Default Enum Value for a property
124+
/// </summary>
125+
/// <param name="entityType">Entity type.</param>
126+
/// <param name="propertyName">Property name.</param>
127+
/// <param name="propertyType">Property type</param>
128+
/// <returns>Default Enumeration Value in format Format will be EnumName.EnumValue</returns>
129+
public string TransformPropertyDefaultEnum(IEntityType entityType, string propertyName, string propertyType)
130+
{
131+
var propTypeInfo = new EntityPropertyInfo { PropertyName = propertyName, PropertyType = propertyType };
132+
if (PropertyTransformer2 != null)
133+
return PropertyTransformer2?.Invoke(entityType, propTypeInfo)?.PropertyDefaultEnumValue;
134+
else if (PropertyTransformer != null)
135+
return PropertyTransformer?.Invoke(propTypeInfo)?.PropertyDefaultEnumValue;
136+
else
137+
return null;
138+
}
139+
98140
/// <summary>
99141
/// Transform single navigation property name.
100142
/// </summary>
@@ -159,7 +201,9 @@ public List<Dictionary<string, object>> TransformProperties(IEntityType entityTy
159201
{
160202
var propTypeInfo = new EntityPropertyInfo(property["property-type"] as string,
161203
property["property-name"] as string,
162-
(property["property-isnullable"] as bool?) == true);
204+
(property["property-isnullable"] as bool?) == true,
205+
(property["property-isenum"] as bool?) == true,
206+
property["property-default-enum"] as string);
163207
EntityPropertyInfo transformedProp;
164208
if (PropertyTransformer2 != null)
165209
transformedProp = PropertyTransformer2?.Invoke(entityType, propTypeInfo);
@@ -170,6 +214,12 @@ public List<Dictionary<string, object>> TransformProperties(IEntityType entityTy
170214
var propertyIsNullable = transformedProp.PropertyIsNullable != null
171215
? transformedProp.PropertyIsNullable
172216
: (bool)property["property-isnullable"];
217+
var isEnumPropertyType = transformedProp.IsEnumPropertyType != null
218+
? transformedProp.IsEnumPropertyType
219+
: (bool)property["property-isenum"];
220+
string propertyDefaultEnumValue = transformedProp.PropertyDefaultEnumValue != null
221+
? transformedProp.PropertyDefaultEnumValue
222+
: property["property-default-enum"] as string;
173223

174224
transformedProperties.Add(new Dictionary<string, object>
175225
{
@@ -178,6 +228,8 @@ public List<Dictionary<string, object>> TransformProperties(IEntityType entityTy
178228
{ "property-annotations", property["property-annotations"] },
179229
{ "property-comment", property["property-comment"] },
180230
{ "property-isnullable", propertyIsNullable },
231+
{ "property-isenum", isEnumPropertyType },
232+
{ "property-default-enum", propertyDefaultEnumValue },
181233
{ "nullable-reference-types", property["nullable-reference-types"] }
182234
});
183235
}

src/EntityFrameworkCore.Scaffolding.Handlebars/HbsTypeScriptEntityTypeGenerator.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ protected virtual void GenerateProperties(IEntityType entityType)
190190
{ "property-annotations", new List<Dictionary<string, object>>() },
191191
{ "property-comment", property.GetComment() },
192192
{ "property-isnullable", property.IsNullable },
193+
{ "property-isenum", false },
194+
{ "property-default-enum", null },
193195
{ "nullable-reference-types", UseNullableReferenceTypes }
194196
});
195197
}

src/EntityFrameworkCore.Scaffolding.Handlebars/IEntityTypeTransformationService.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,25 @@ public interface IEntityTypeTransformationService
4040
/// <returns>Transformed property name.</returns>
4141
string TransformNavPropertyName(IEntityType entityType, string propertyName, string propertyType);
4242

43+
/// <summary>
44+
/// Transforms the Property Type if it is an Enumeration.
45+
/// Returns null when not an Enumeration
46+
/// </summary>
47+
/// <param name="entityType">Entity type.</param>
48+
/// <param name="propertyName">Property name.</param>
49+
/// <param name="propertyType">Property type</param>
50+
/// <returns>Transformed property name, null when not an Enumeration</returns>
51+
public string TransformPropertyTypeIfEnumaration(IEntityType entityType, string propertyName, string propertyType);
52+
53+
/// <summary>
54+
/// Transform Default Enum Value for a property
55+
/// </summary>
56+
/// <param name="entityType">Entity type.</param>
57+
/// <param name="propertyName">Property name.</param>
58+
/// <param name="propertyType">Property type</param>
59+
/// <returns>Default Enumeration Value in format Format will be EnumName.EnumValue</returns>
60+
public string TransformPropertyDefaultEnum(IEntityType entityType, string propertyName, string propertyType);
61+
4362
/// <summary>
4463
/// Transform entity type constructor.
4564
/// </summary>

src/EntityFrameworkCore.Scaffolding.Handlebars/Internal/EntityTypeExtensions.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,36 @@ public static class EntityTypeExtensions
2121
public static IEnumerable<IPropertyBase> GetPropertiesAndNavigations(
2222
this IEntityType entityType)
2323
=> entityType.GetProperties().Concat<IPropertyBase>(entityType.GetNavigations());
24+
25+
/// <summary>
26+
/// Determines if the given <see cref="IEntityType"/> is a join entity
27+
/// type for a many-to-many relationship where Entity would not be generated.
28+
/// This is where only Key properties are present.
29+
/// </summary>
30+
/// <param name="entityType">Entity Type</param>
31+
/// <returns></returns>
32+
public static bool IsManyToManyJoinEntityType(this IEntityType entityType)
33+
{
34+
if (!entityType.GetNavigations().Any()
35+
&& !entityType.GetSkipNavigations().Any())
36+
{
37+
var primaryKey = entityType.FindPrimaryKey();
38+
var properties = entityType.GetProperties().ToList();
39+
var foreignKeys = entityType.GetForeignKeys().ToList();
40+
if (primaryKey != null
41+
&& primaryKey.Properties.Count > 1
42+
&& foreignKeys.Count == 2
43+
&& primaryKey.Properties.Count == properties.Count
44+
&& foreignKeys[0].Properties.Count + foreignKeys[1].Properties.Count == properties.Count
45+
&& !foreignKeys[0].Properties.Intersect(foreignKeys[1].Properties).Any()
46+
&& foreignKeys[0].IsRequired
47+
&& foreignKeys[1].IsRequired
48+
&& !foreignKeys[0].IsUnique
49+
&& !foreignKeys[1].IsUnique)
50+
{
51+
return true;
52+
}
53+
}
54+
return false;
55+
}
2456
}

0 commit comments

Comments
 (0)