diff --git a/src/EFCore.Design/Extensions/ScaffoldingModelExtensions.cs b/src/EFCore.Design/Extensions/ScaffoldingModelExtensions.cs
index 1fe38f60993..86a430dc6b8 100644
--- a/src/EFCore.Design/Extensions/ScaffoldingModelExtensions.cs
+++ b/src/EFCore.Design/Extensions/ScaffoldingModelExtensions.cs
@@ -10,15 +10,15 @@
namespace Microsoft.EntityFrameworkCore;
///
-/// Design-time model extensions.
+/// Design-time model extensions.
///
public static class ScaffoldingModelExtensions
{
///
- /// Check whether an entity type could be considered a many-to-many join entity type.
+ /// Check whether an entity type could be considered a many-to-many join entity type.
///
/// The entity type to check.
- /// if the entity type could be considered a join entity type.
+ /// if the entity type could be considered a join entity type.
public static bool IsSimpleManyToManyJoinEntityType(this IEntityType entityType)
{
if (!entityType.GetNavigations().Any()
@@ -46,18 +46,21 @@ public static bool IsSimpleManyToManyJoinEntityType(this IEntityType entityType)
}
///
- /// Gets a value indicating whether the specified skip navigation represents the left side of the relationship.
+ /// Gets a value indicating whether the specified skip navigation represents the left side of the relationship.
///
/// The skip navigation to check.
- /// if it represents the left side.
+ /// if it represents the left side.
///
- /// The designation of left and right is arbitrary but deterministic. This method exists primarily to avoid configuring the same many-to-many relationship from both of its ends.
+ /// The designation of left and right is arbitrary but deterministic. This method exists primarily to avoid configuring the same
+ /// many-to-many relationship from both of its ends.
///
public static bool IsLeftNavigation(this ISkipNavigation skipNavigation)
- => skipNavigation.JoinEntityType.FindPrimaryKey()!.Properties[0].GetContainingForeignKeys().Single().PrincipalEntityType == skipNavigation.DeclaringEntityType;
+ => skipNavigation.JoinEntityType.FindPrimaryKey()!.Properties[0].GetContainingForeignKeys().Single().PrincipalEntityType
+ == skipNavigation.DeclaringEntityType;
///
- /// Gets the name that should be used for the property on the class for this entity type.
+ /// Gets the name that should be used for the property on the class for this entity
+ /// type.
///
/// The entity type.
/// The property name.
@@ -66,10 +69,10 @@ public static string GetDbSetName(this IReadOnlyEntityType entityType)
?? entityType.ShortName();
///
- /// Gets a value indicating whether the key would be configured by conventions.
+ /// Gets a value indicating whether the key would be configured by conventions.
///
/// The key to check.
- /// if the key would be configured by conventions.
+ /// if the key would be configured by conventions.
public static bool IsHandledByConventions(this IKey key)
=> key is IConventionKey conventionKey
&& conventionKey.Properties.SequenceEqual(
@@ -78,11 +81,11 @@ public static bool IsHandledByConventions(this IKey key)
conventionKey.DeclaringEntityType.GetProperties()));
///
- /// Gets value indicating whether this index can be entirely reperesented by a data annotation.
+ /// Gets value indicating whether this index can be entirely reperesented by a data annotation.
///
/// The index.
/// The provider's annotation code generator.
- /// if this index can be reperesented by a data annotation.
+ /// if this index can be reperesented by a data annotation.
public static bool HasDataAnnotation(this IIndex index, IAnnotationCodeGenerator annotationCodeGenerator)
{
var indexAnnotations = annotationCodeGenerator.FilterIgnoredAnnotations(index.GetAnnotations())
@@ -94,17 +97,26 @@ public static bool HasDataAnnotation(this IIndex index, IAnnotationCodeGenerator
}
///
- /// Gets the data annotations to configure an entity type.
+ /// Gets the data annotations to configure an entity type.
///
/// The entity type.
/// The provider's annotation code generator.
/// The data annotations.
- public static IEnumerable GetDataAnnotations(this IEntityType entityType, IAnnotationCodeGenerator annotationCodeGenerator)
+ public static IEnumerable GetDataAnnotations(
+ this IEntityType entityType,
+ IAnnotationCodeGenerator annotationCodeGenerator)
{
- if (entityType.FindPrimaryKey() == null)
+ var primaryKey = entityType.FindPrimaryKey();
+ if (primaryKey == null)
{
yield return new AttributeCodeFragment(typeof(KeylessAttribute));
}
+ else if (primaryKey.Properties.Count > 1)
+ {
+ yield return new AttributeCodeFragment(
+ typeof(PrimaryKeyAttribute),
+ primaryKey.Properties.Select(p => p.Name).Cast().ToArray());
+ }
var tableName = entityType.GetTableName();
var schema = entityType.GetSchema();
@@ -118,14 +130,15 @@ public static IEnumerable GetDataAnnotations(this IEntity
if (needsSchema)
{
tableNamedArgs.Add(nameof(TableAttribute.Schema), schema);
- };
+ }
yield return new AttributeCodeFragment(typeof(TableAttribute), new object?[] { tableName }, tableNamedArgs);
}
foreach (var index in entityType.GetIndexes()
- .Where(i => ((IConventionIndex)i).GetConfigurationSource() != ConfigurationSource.Convention
- && i.HasDataAnnotation(annotationCodeGenerator)))
+ .Where(
+ i => ((IConventionIndex)i).GetConfigurationSource() != ConfigurationSource.Convention
+ && i.HasDataAnnotation(annotationCodeGenerator)))
{
var indexArgs = new List();
var indexNamedArgs = new Dictionary();
@@ -167,12 +180,14 @@ public static IEnumerable GetDataAnnotations(this IEntity
}
///
- /// Gets the data annotations to configure a property.
+ /// Gets the data annotations to configure a property.
///
/// The property.
/// The provider's annotation code generator.
/// The data annotations.
- public static IEnumerable GetDataAnnotations(this IProperty property, IAnnotationCodeGenerator annotationCodeGenerator)
+ public static IEnumerable GetDataAnnotations(
+ this IProperty property,
+ IAnnotationCodeGenerator annotationCodeGenerator)
{
if (property.FindContainingPrimaryKey() != null)
{
@@ -263,12 +278,14 @@ public static IEnumerable GetDataAnnotations(this IProper
}
///
- /// Gets the data annotations to configure a navigation property.
+ /// Gets the data annotations to configure a navigation property.
///
/// The navigation property.
/// The provider's annotation code generator.
/// The data annotations.
- public static IEnumerable GetDataAnnotations(this INavigation navigation, IAnnotationCodeGenerator annotationCodeGenerator)
+ public static IEnumerable GetDataAnnotations(
+ this INavigation navigation,
+ IAnnotationCodeGenerator annotationCodeGenerator)
{
if (navigation.IsOnDependent
&& navigation.ForeignKey.PrincipalKey.IsPrimaryKey())
@@ -286,12 +303,14 @@ public static IEnumerable GetDataAnnotations(this INaviga
}
///
- /// Gets the data annotations to configure a skip navigation property.
+ /// Gets the data annotations to configure a skip navigation property.
///
/// The skip navigation property.
/// The provider's annotation code generator.
/// The data annotations.
- public static IEnumerable GetDataAnnotations(this ISkipNavigation skipNavigation, IAnnotationCodeGenerator annotationCodeGenerator)
+ public static IEnumerable GetDataAnnotations(
+ this ISkipNavigation skipNavigation,
+ IAnnotationCodeGenerator annotationCodeGenerator)
{
if (skipNavigation.ForeignKey!.PrincipalKey.IsPrimaryKey())
{
@@ -304,7 +323,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
}
///
- /// Gets the fluent API calls to configure a model.
+ /// Gets the fluent API calls to configure a model.
///
/// The model.
/// The provider's annotation code generator.
@@ -331,13 +350,14 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
}
///
- /// Gets the fluent API calls to configure an entity type.
+ /// Gets the fluent API calls to configure an entity type.
///
/// The entity type.
/// The provider's annotation code generator.
/// The fluent API calls.
public static FluentApiCodeFragment? GetFluentApiCalls(
- this IEntityType entityType, IAnnotationCodeGenerator annotationCodeGenerator)
+ this IEntityType entityType,
+ IAnnotationCodeGenerator annotationCodeGenerator)
{
FluentApiCodeFragment? root = null;
@@ -365,10 +385,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
if (entityType.FindPrimaryKey() is null)
{
- var hasNoKey = new FluentApiCodeFragment(nameof(EntityTypeBuilder.HasNoKey))
- {
- HasDataAnnotation = true
- };
+ var hasNoKey = new FluentApiCodeFragment(nameof(EntityTypeBuilder.HasNoKey)) { HasDataAnnotation = true };
root = root?.Chain(hasNoKey) ?? hasNoKey;
}
@@ -424,10 +441,10 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
{
toTableArguments.Add(new NestedClosureCodeFragment("tb", toTableNestedCalls));
}
+
var toTable = new FluentApiCodeFragment(nameof(RelationalEntityTypeBuilderExtensions.ToTable))
{
- Arguments = toTableArguments,
- HasDataAnnotation = toTableHandledByDataAnnotations
+ Arguments = toTableArguments, HasDataAnnotation = toTableHandledByDataAnnotations
};
root = root?.Chain(toTable) ?? toTable;
@@ -440,10 +457,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
if (explicitViewSchema
|| viewName != null)
{
- var toView = new FluentApiCodeFragment(nameof(RelationalEntityTypeBuilderExtensions.ToView))
- {
- Arguments = { viewName }
- };
+ var toView = new FluentApiCodeFragment(nameof(RelationalEntityTypeBuilderExtensions.ToView)) { Arguments = { viewName } };
if (explicitViewSchema)
{
@@ -459,7 +473,8 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
root = root?.Chain(annotationsRoot) ?? annotationsRoot;
}
- annotationsRoot = GenerateAnnotations(entityType, annotationsHandledByDataAnnotations, annotationCodeGenerator, hasDataAnnotation: true);
+ annotationsRoot = GenerateAnnotations(
+ entityType, annotationsHandledByDataAnnotations, annotationCodeGenerator, hasDataAnnotation: true);
if (annotationsRoot is not null)
{
root = root?.Chain(annotationsRoot) ?? annotationsRoot;
@@ -469,7 +484,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
}
///
- /// Gets the fluent API calls to configure a key.
+ /// Gets the fluent API calls to configure a key.
///
/// The key.
/// The provider's annotation code generator.
@@ -492,7 +507,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
}
///
- /// Gets the fluent API calls to configure an index.
+ /// Gets the fluent API calls to configure an index.
///
/// The index.
/// The provider's annotation code generator.
@@ -534,7 +549,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
}
///
- /// Gets the fluent API calls to configure a property.
+ /// Gets the fluent API calls to configure a property.
///
/// The property.
/// The provider's annotation code generator.
@@ -566,10 +581,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
&& property.ClrType.IsNullableType()
&& !property.IsPrimaryKey())
{
- var isRequired = new FluentApiCodeFragment(nameof(PropertyBuilder.IsRequired))
- {
- HasDataAnnotation = true
- };
+ var isRequired = new FluentApiCodeFragment(nameof(PropertyBuilder.IsRequired)) { HasDataAnnotation = true };
root = root?.Chain(isRequired) ?? isRequired;
}
@@ -579,8 +591,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
{
var hasMaxLength = new FluentApiCodeFragment(nameof(PropertyBuilder.HasMaxLength))
{
- Arguments = { maxLength.Value },
- HasDataAnnotation = true
+ Arguments = { maxLength.Value }, HasDataAnnotation = true
};
root = root?.Chain(hasMaxLength) ?? hasMaxLength;
@@ -592,12 +603,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
{
var hasPrecision = new FluentApiCodeFragment(nameof(PropertyBuilder.HasPrecision))
{
- Arguments =
- {
- precision.Value,
- scale.Value
- },
- HasDataAnnotation = true
+ Arguments = { precision.Value, scale.Value }, HasDataAnnotation = true
};
root = root?.Chain(hasPrecision) ?? hasPrecision;
@@ -606,8 +612,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
{
var hasPrecision = new FluentApiCodeFragment(nameof(PropertyBuilder.HasPrecision))
{
- Arguments = { precision.Value },
- HasDataAnnotation = true
+ Arguments = { precision.Value }, HasDataAnnotation = true
};
root = root?.Chain(hasPrecision) ?? hasPrecision;
@@ -615,10 +620,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
if (property.IsUnicode() != null)
{
- var isUnicode = new FluentApiCodeFragment(nameof(PropertyBuilder.IsUnicode))
- {
- HasDataAnnotation = true
- };
+ var isUnicode = new FluentApiCodeFragment(nameof(PropertyBuilder.IsUnicode)) { HasDataAnnotation = true };
if (property.IsUnicode() == false)
{
@@ -662,7 +664,8 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
root = root?.Chain(annotationsRoot) ?? annotationsRoot;
}
- annotationsRoot = GenerateAnnotations(property, annotationsHandledByDataAnnotations, annotationCodeGenerator, hasDataAnnotation: true);
+ annotationsRoot = GenerateAnnotations(
+ property, annotationsHandledByDataAnnotations, annotationCodeGenerator, hasDataAnnotation: true);
if (annotationsRoot is not null)
{
root = root?.Chain(annotationsRoot) ?? annotationsRoot;
@@ -672,13 +675,16 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
}
///
- /// Gets the fluent API calls to configure a foreign key.
+ /// Gets the fluent API calls to configure a foreign key.
///
/// The foreign key.
/// The provider's annotation code generator.
/// A value indicating wheter to use string fluent API overloads instead of ones that take a property accessor lambda.
/// The fluent API calls.
- public static FluentApiCodeFragment? GetFluentApiCalls(this IForeignKey foreignKey, IAnnotationCodeGenerator annotationCodeGenerator, bool useStrings = false)
+ public static FluentApiCodeFragment? GetFluentApiCalls(
+ this IForeignKey foreignKey,
+ IAnnotationCodeGenerator annotationCodeGenerator,
+ bool useStrings = false)
{
FluentApiCodeFragment? root = null;
@@ -709,10 +715,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
root = root?.Chain(hasPrincipalKey) ?? hasPrincipalKey;
}
- var hasForeignKey = new FluentApiCodeFragment(nameof(ReferenceReferenceBuilder.HasForeignKey))
- {
- HasDataAnnotation = true
- };
+ var hasForeignKey = new FluentApiCodeFragment(nameof(ReferenceReferenceBuilder.HasForeignKey)) { HasDataAnnotation = true };
if (foreignKey.IsUnique)
{
@@ -754,7 +757,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
}
///
- /// Gets the fluent API calls to configure a sequence.
+ /// Gets the fluent API calls to configure a sequence.
///
/// The sequence.
/// The provider's annotation code generator.
@@ -765,40 +768,28 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
if (sequence.StartValue != Sequence.DefaultStartValue)
{
- var startsAt = new FluentApiCodeFragment(nameof(SequenceBuilder.StartsAt))
- {
- Arguments = { sequence.StartValue }
- };
+ var startsAt = new FluentApiCodeFragment(nameof(SequenceBuilder.StartsAt)) { Arguments = { sequence.StartValue } };
root = root?.Chain(startsAt) ?? startsAt;
}
if (sequence.IncrementBy != Sequence.DefaultIncrementBy)
{
- var incrementsBy = new FluentApiCodeFragment(nameof(SequenceBuilder.IncrementsBy))
- {
- Arguments = { sequence.IncrementBy }
- };
+ var incrementsBy = new FluentApiCodeFragment(nameof(SequenceBuilder.IncrementsBy)) { Arguments = { sequence.IncrementBy } };
root = root?.Chain(incrementsBy) ?? incrementsBy;
}
if (sequence.MinValue != Sequence.DefaultMinValue)
{
- var hasMin = new FluentApiCodeFragment(nameof(SequenceBuilder.HasMin))
- {
- Arguments = { sequence.MinValue }
- };
+ var hasMin = new FluentApiCodeFragment(nameof(SequenceBuilder.HasMin)) { Arguments = { sequence.MinValue } };
root = root?.Chain(hasMin) ?? hasMin;
}
if (sequence.MaxValue != Sequence.DefaultMaxValue)
{
- var hasMax = new FluentApiCodeFragment(nameof(SequenceBuilder.HasMax))
- {
- Arguments = { sequence.MaxValue }
- };
+ var hasMax = new FluentApiCodeFragment(nameof(SequenceBuilder.HasMax)) { Arguments = { sequence.MaxValue } };
root = root?.Chain(hasMax) ?? hasMax;
}
@@ -813,7 +804,11 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
return root;
}
- private static FluentApiCodeFragment? GenerateAnnotations(IAnnotatable annotatable, Dictionary annotations, IAnnotationCodeGenerator annotationCodeGenerator, bool hasDataAnnotation = false)
+ private static FluentApiCodeFragment? GenerateAnnotations(
+ IAnnotatable annotatable,
+ Dictionary annotations,
+ IAnnotationCodeGenerator annotationCodeGenerator,
+ bool hasDataAnnotation = false)
{
FluentApiCodeFragment? root = null;
@@ -829,12 +824,7 @@ public static IEnumerable GetDataAnnotations(this ISkipNa
{
var hasAnnotation = new FluentApiCodeFragment(nameof(ModelBuilder.HasAnnotation))
{
- Arguments =
- {
- annotation.Name,
- annotation.Value
- },
- HasDataAnnotation = hasDataAnnotation
+ Arguments = { annotation.Name, annotation.Value }, HasDataAnnotation = hasDataAnnotation
};
root = root?.Chain(hasAnnotation) ?? hasAnnotation;
diff --git a/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs b/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs
index f9497d6cbb4..bb659443443 100644
--- a/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs
+++ b/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.cs
@@ -149,7 +149,6 @@ public virtual string TransformText()
{
var keyFluentApiCalls = key.GetFluentApiCalls(annotationCodeGenerator);
if (keyFluentApiCalls != null
- || key.Properties.Count > 1
|| (!key.IsHandledByConventions() && !Options.UseDataAnnotations))
{
if (keyFluentApiCalls != null)
diff --git a/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.tt b/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.tt
index ca6309261e9..02971eb93ba 100644
--- a/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.tt
+++ b/src/EFCore.Design/Scaffolding/Internal/CSharpDbContextGenerator.tt
@@ -122,7 +122,6 @@ public partial class <#= Options.ContextName #> : DbContext
{
var keyFluentApiCalls = key.GetFluentApiCalls(annotationCodeGenerator);
if (keyFluentApiCalls != null
- || key.Properties.Count > 1
|| (!key.IsHandledByConventions() && !Options.UseDataAnnotations))
{
if (keyFluentApiCalls != null)
diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs
index 6814231614d..f7466dbf537 100644
--- a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs
+++ b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpEntityTypeGeneratorTest.cs
@@ -531,7 +531,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
Assert.Equal("PrimaryKey", model.FindEntityType("TestNamespace.Entity").FindPrimaryKey().Properties[0].Name));
[ConditionalFact]
- public void KeyAttribute_is_generated_on_multiple_properties_but_configuring_using_fluent_api_for_composite_key()
+ public void KeyAttribute_is_generated_on_multiple_properties_but_and_uses_PrimaryKeyAttribute_for_composite_key()
=> Test(
modelBuilder => modelBuilder
.Entity(
@@ -554,6 +554,7 @@ public void KeyAttribute_is_generated_on_multiple_properties_but_configuring_usi
namespace TestNamespace;
+[PrimaryKey(""Key"", ""Serial"")]
public partial class Post
{
[Key]
@@ -593,11 +594,6 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
- modelBuilder.Entity(entity =>
- {
- entity.HasKey(e => new { e.Key, e.Serial });
- });
-
OnModelCreatingPartial(modelBuilder);
}
@@ -1531,11 +1527,6 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
- modelBuilder.Entity(entity =>
- {
- entity.HasKey(e => new { e.Id1, e.Id2 });
- });
-
modelBuilder.Entity(entity =>
{
entity.Property(e => e.Id).UseIdentityColumn();