diff --git a/src/EFCore.Relational/Extensions/RelationalKeyBuilderExtensions.cs b/src/EFCore.Relational/Extensions/RelationalKeyBuilderExtensions.cs
index c7ee6eead7e..e88fcafc250 100644
--- a/src/EFCore.Relational/Extensions/RelationalKeyBuilderExtensions.cs
+++ b/src/EFCore.Relational/Extensions/RelationalKeyBuilderExtensions.cs
@@ -30,6 +30,17 @@ public static KeyBuilder HasName([NotNull] this KeyBuilder keyBuilder, [CanBeNul
return keyBuilder;
}
+ ///
+ /// Configures the name of the key constraint in the database when targeting a relational database.
+ ///
+ /// The builder for the key being configured.
+ /// The name of the key.
+ /// The same builder instance so that multiple calls can be chained.
+ public static KeyBuilder HasName(
+ [NotNull] this KeyBuilder keyBuilder,
+ [CanBeNull] string name)
+ => (KeyBuilder)HasName((KeyBuilder)keyBuilder, name);
+
///
/// Configures the name of the key constraint in the database when targeting a relational database.
///
diff --git a/src/EFCore.SqlServer/Extensions/SqlServerKeyBuilderExtensions.cs b/src/EFCore.SqlServer/Extensions/SqlServerKeyBuilderExtensions.cs
index beb40ecc6da..7168df2b1b1 100644
--- a/src/EFCore.SqlServer/Extensions/SqlServerKeyBuilderExtensions.cs
+++ b/src/EFCore.SqlServer/Extensions/SqlServerKeyBuilderExtensions.cs
@@ -29,6 +29,16 @@ public static KeyBuilder IsClustered([NotNull] this KeyBuilder keyBuilder, bool
return keyBuilder;
}
+ ///
+ /// Configures whether the key is clustered when targeting SQL Server.
+ ///
+ /// The builder for the key being configured.
+ /// A value indicating whether the key is clustered.
+ /// The same builder instance so that multiple calls can be chained.
+ public static KeyBuilder IsClustered(
+ [NotNull] this KeyBuilder keyBuilder, bool clustered = true)
+ => (KeyBuilder)IsClustered((KeyBuilder)keyBuilder, clustered);
+
///
/// Configures whether the key is clustered when targeting SQL Server.
///
diff --git a/src/EFCore/Metadata/Builders/EntityTypeBuilder`.cs b/src/EFCore/Metadata/Builders/EntityTypeBuilder`.cs
index 92dee289d1a..1fa0f0ce634 100644
--- a/src/EFCore/Metadata/Builders/EntityTypeBuilder`.cs
+++ b/src/EFCore/Metadata/Builders/EntityTypeBuilder`.cs
@@ -85,12 +85,22 @@ public virtual EntityTypeBuilder HasBaseType()
///
///
/// An object that can be used to configure the primary key.
- public virtual KeyBuilder HasKey([NotNull] Expression> keyExpression)
- => new KeyBuilder(
+ public virtual KeyBuilder HasKey([NotNull] Expression> keyExpression)
+ => new KeyBuilder(
Builder.PrimaryKey(
Check.NotNull(keyExpression, nameof(keyExpression)).GetPropertyAccessList(),
ConfigurationSource.Explicit).Metadata);
+ ///
+ /// Sets the properties that make up the primary key for this entity type.
+ ///
+ /// The names of the properties that make up the primary key.
+ /// An object that can be used to configure the primary key.
+ public new virtual KeyBuilder HasKey([NotNull] params string[] propertyNames)
+ => new KeyBuilder(
+ Builder.PrimaryKey(
+ Check.NotEmpty(propertyNames, nameof(propertyNames)), ConfigurationSource.Explicit).Metadata);
+
///
/// Creates an alternate key in the model for this entity type if one does not already exist over the specified
/// properties. This will force the properties to be read-only. Use to specify uniqueness
@@ -106,12 +116,24 @@ public virtual KeyBuilder HasKey([NotNull] Expression> key
///
///
/// An object that can be used to configure the key.
- public virtual KeyBuilder HasAlternateKey([NotNull] Expression> keyExpression)
- => new KeyBuilder(
+ public virtual KeyBuilder HasAlternateKey([NotNull] Expression> keyExpression)
+ => new KeyBuilder(
Builder.HasKey(
Check.NotNull(keyExpression, nameof(keyExpression)).GetPropertyAccessList(),
ConfigurationSource.Explicit).Metadata);
+ ///
+ /// Creates an alternate key in the model for this entity type if one does not already exist over the specified
+ /// properties. This will force the properties to be read-only. Use to specify uniqueness
+ /// in the model that does not force properties to be read-only.
+ ///
+ /// The names of the properties that make up the key.
+ /// An object that can be used to configure the key.
+ public new virtual KeyBuilder HasAlternateKey([NotNull] params string[] propertyNames)
+ => new KeyBuilder(
+ Builder.HasKey(
+ Check.NotEmpty(propertyNames, nameof(propertyNames)), ConfigurationSource.Explicit).Metadata);
+
///
/// Configures the entity type to have no keys. It will only be usable for queries.
///
diff --git a/src/EFCore/Metadata/Builders/KeyBuilder`.cs b/src/EFCore/Metadata/Builders/KeyBuilder`.cs
new file mode 100644
index 00000000000..2f548a6cf0d
--- /dev/null
+++ b/src/EFCore/Metadata/Builders/KeyBuilder`.cs
@@ -0,0 +1,43 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using JetBrains.Annotations;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+
+namespace Microsoft.EntityFrameworkCore.Metadata.Builders
+{
+ ///
+ ///
+ /// Provides a simple API for configuring a .
+ ///
+ ///
+ /// Instances of this class are returned from methods when using the API
+ /// and it is not designed to be directly constructed in your application code.
+ ///
+ ///
+ // ReSharper disable once UnusedTypeParameter
+ public class KeyBuilder : KeyBuilder
+ {
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ [EntityFrameworkInternal]
+ public KeyBuilder([NotNull] IMutableKey key)
+ : base(key)
+ {
+ }
+
+ ///
+ /// Adds or updates an annotation on the key. If an annotation with the key specified in
+ /// already exists its value will be updated.
+ ///
+ /// The key of the annotation to be added or updated.
+ /// The value to be stored in the annotation.
+ /// The same builder instance so that multiple configuration calls can be chained.
+ public new virtual KeyBuilder HasAnnotation([NotNull] string annotation, [NotNull] object value)
+ => (KeyBuilder)base.HasAnnotation(annotation, value);
+ }
+}
diff --git a/src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs b/src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs
index a7e391e8e64..300fe68989b 100644
--- a/src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs
+++ b/src/EFCore/Metadata/Builders/OwnedNavigationBuilder`.cs
@@ -59,11 +59,21 @@ public OwnedNavigationBuilder(
///
///
/// An object that can be used to configure the primary key.
- public virtual KeyBuilder HasKey([NotNull] Expression> keyExpression)
- => new KeyBuilder(
+ public virtual KeyBuilder HasKey([NotNull] Expression> keyExpression)
+ => new KeyBuilder(
DependentEntityType.Builder.PrimaryKey(
Check.NotNull(keyExpression, nameof(keyExpression)).GetPropertyAccessList(), ConfigurationSource.Explicit).Metadata);
+ ///
+ /// Sets the properties that make up the primary key for this owned entity type.
+ ///
+ /// The names of the properties that make up the primary key.
+ /// An object that can be used to configure the primary key.
+ public new virtual KeyBuilder HasKey([NotNull] params string[] propertyNames)
+ => new KeyBuilder(
+ DependentEntityType.Builder.PrimaryKey(
+ Check.NotEmpty(propertyNames, nameof(propertyNames)), ConfigurationSource.Explicit).Metadata);
+
///
///
/// Returns an object that can be used to configure a property of the owned entity type.
diff --git a/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs b/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs
index 15195f14e90..44512ce978a 100644
--- a/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs
+++ b/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs
@@ -247,11 +247,19 @@ public static ModelBuilderTest.TestIndexBuilder HasName(
return builder;
}
- public static ModelBuilderTest.TestKeyBuilder HasName(
- this ModelBuilderTest.TestKeyBuilder builder, string name)
+ public static ModelBuilderTest.TestKeyBuilder HasName(
+ this ModelBuilderTest.TestKeyBuilder builder, string name)
{
- var keyBuilder = builder.GetInfrastructure();
- keyBuilder.HasName(name);
+ switch (builder)
+ {
+ case IInfrastructure> genericBuilder:
+ genericBuilder.Instance.HasName(name);
+ break;
+ case IInfrastructure nongenericBuilder:
+ nongenericBuilder.Instance.HasName(name);
+ break;
+ }
+
return builder;
}
}
diff --git a/test/EFCore.Tests/Metadata/MetadataBuilderTest.cs b/test/EFCore.Tests/Metadata/MetadataBuilderTest.cs
index b91d353e7ce..827cb68c12b 100644
--- a/test/EFCore.Tests/Metadata/MetadataBuilderTest.cs
+++ b/test/EFCore.Tests/Metadata/MetadataBuilderTest.cs
@@ -100,7 +100,7 @@ public void Can_write_convention_key_builder_extension()
.KeyBuilderExtension("V1")
.KeyBuilderExtension("V2");
- Assert.IsType(returnedBuilder);
+ Assert.IsType>(returnedBuilder);
var model = builder.Model;
var key = model.FindEntityType(typeof(Gunter)).FindPrimaryKey();
@@ -298,7 +298,7 @@ public void Can_write_convention_key_builder_extension_with_common_name()
.SharedNameExtension("V1")
.SharedNameExtension("V2");
- Assert.IsType(returnedBuilder);
+ Assert.IsType>(returnedBuilder);
var model = builder.Model;
var key = model.FindEntityType(typeof(Gunter)).FindPrimaryKey();
diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs
index 799b6514257..2af3faea903 100644
--- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs
+++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs
@@ -181,17 +181,17 @@ public override TestEntityTypeBuilder HasBaseType()
public override TestEntityTypeBuilder HasBaseType(string baseEntityTypeName)
=> Wrap(EntityTypeBuilder.HasBaseType(baseEntityTypeName));
- public override TestKeyBuilder HasKey(Expression> keyExpression)
- => new TestKeyBuilder(EntityTypeBuilder.HasKey(keyExpression));
+ public override TestKeyBuilder HasKey(Expression> keyExpression)
+ => new GenericTestKeyBuilder(EntityTypeBuilder.HasKey(keyExpression));
- public override TestKeyBuilder HasKey(params string[] propertyNames)
- => new TestKeyBuilder(EntityTypeBuilder.HasKey(propertyNames));
+ public override TestKeyBuilder HasKey(params string[] propertyNames)
+ => new GenericTestKeyBuilder(EntityTypeBuilder.HasKey(propertyNames));
- public override TestKeyBuilder HasAlternateKey(Expression> keyExpression)
- => new TestKeyBuilder(EntityTypeBuilder.HasAlternateKey(keyExpression));
+ public override TestKeyBuilder HasAlternateKey(Expression> keyExpression)
+ => new GenericTestKeyBuilder(EntityTypeBuilder.HasAlternateKey(keyExpression));
- public override TestKeyBuilder HasAlternateKey(params string[] propertyNames)
- => new TestKeyBuilder(EntityTypeBuilder.HasAlternateKey(propertyNames));
+ public override TestKeyBuilder HasAlternateKey(params string[] propertyNames)
+ => new GenericTestKeyBuilder(EntityTypeBuilder.HasAlternateKey(propertyNames));
public override TestEntityTypeBuilder HasNoKey()
=> Wrap(EntityTypeBuilder.HasNoKey());
@@ -441,6 +441,23 @@ public override TestPropertyBuilder HasConversion(ValueConverter conv
PropertyBuilder IInfrastructure>.Instance => PropertyBuilder;
}
+ protected class GenericTestKeyBuilder : TestKeyBuilder, IInfrastructure>
+ {
+ public GenericTestKeyBuilder(KeyBuilder keyBuilder)
+ {
+ KeyBuilder = keyBuilder;
+ }
+
+ private KeyBuilder KeyBuilder { get; }
+
+ public override IMutableKey Metadata => KeyBuilder.Metadata;
+
+ public override TestKeyBuilder HasAnnotation(string annotation, object value)
+ => new GenericTestKeyBuilder(KeyBuilder.HasAnnotation(annotation, value));
+
+ KeyBuilder IInfrastructure>.Instance => KeyBuilder;
+ }
+
protected class GenericTestNavigationBuilder : TestNavigationBuilder
{
public GenericTestNavigationBuilder(NavigationBuilder navigationBuilder)
@@ -713,11 +730,11 @@ public override TestOwnedNavigationBuilder HasAnnotat
string annotation, object value)
=> Wrap(OwnedNavigationBuilder.HasAnnotation(annotation, value));
- public override TestKeyBuilder HasKey(Expression> keyExpression)
- => new TestKeyBuilder(OwnedNavigationBuilder.HasKey(keyExpression));
+ public override TestKeyBuilder HasKey(Expression> keyExpression)
+ => new GenericTestKeyBuilder(OwnedNavigationBuilder.HasKey(keyExpression));
- public override TestKeyBuilder HasKey(params string[] propertyNames)
- => new TestKeyBuilder(OwnedNavigationBuilder.HasKey(propertyNames));
+ public override TestKeyBuilder HasKey(params string[] propertyNames)
+ => new GenericTestKeyBuilder(OwnedNavigationBuilder.HasKey(propertyNames));
public override TestPropertyBuilder Property(string propertyName)
=> new GenericTestPropertyBuilder(OwnedNavigationBuilder.Property(propertyName));
diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs
index b1f04120b6c..15a80b862a8 100644
--- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs
+++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs
@@ -116,20 +116,20 @@ public override TestEntityTypeBuilder HasBaseType()
public override TestEntityTypeBuilder HasBaseType(string baseEntityTypeName)
=> Wrap(EntityTypeBuilder.HasBaseType(baseEntityTypeName));
- public override TestKeyBuilder HasKey(Expression> keyExpression)
- => new TestKeyBuilder(
+ public override TestKeyBuilder HasKey(Expression> keyExpression)
+ => new NonGenericTestKeyBuilder(
EntityTypeBuilder.HasKey(keyExpression.GetPropertyAccessList().Select(p => p.GetSimpleMemberName()).ToArray()));
- public override TestKeyBuilder HasKey(params string[] propertyNames)
- => new TestKeyBuilder(EntityTypeBuilder.HasKey(propertyNames));
+ public override TestKeyBuilder HasKey(params string[] propertyNames)
+ => new NonGenericTestKeyBuilder(EntityTypeBuilder.HasKey(propertyNames));
- public override TestKeyBuilder HasAlternateKey(Expression> keyExpression)
- => new TestKeyBuilder(
+ public override TestKeyBuilder HasAlternateKey(Expression> keyExpression)
+ => new NonGenericTestKeyBuilder(
EntityTypeBuilder.HasAlternateKey(
keyExpression.GetPropertyAccessList().Select(p => p.GetSimpleMemberName()).ToArray()));
- public override TestKeyBuilder HasAlternateKey(params string[] propertyNames)
- => new TestKeyBuilder(EntityTypeBuilder.HasAlternateKey(propertyNames));
+ public override TestKeyBuilder HasAlternateKey(params string[] propertyNames)
+ => new NonGenericTestKeyBuilder(EntityTypeBuilder.HasAlternateKey(propertyNames));
public override TestEntityTypeBuilder HasNoKey()
=> Wrap(EntityTypeBuilder.HasNoKey());
@@ -429,6 +429,23 @@ public override TestNavigationBuilder UsePropertyAccessMode(PropertyAccessMode p
=> new NonGenericTestNavigationBuilder(NavigationBuilder.UsePropertyAccessMode(propertyAccessMode));
}
+ protected class NonGenericTestKeyBuilder : TestKeyBuilder, IInfrastructure
+ {
+ public NonGenericTestKeyBuilder(KeyBuilder keyBuilder)
+ {
+ KeyBuilder = keyBuilder;
+ }
+
+ private KeyBuilder KeyBuilder { get; }
+
+ public override IMutableKey Metadata => KeyBuilder.Metadata;
+
+ public override TestKeyBuilder HasAnnotation(string annotation, object value)
+ => new NonGenericTestKeyBuilder(KeyBuilder.HasAnnotation(annotation, value));
+
+ KeyBuilder IInfrastructure.Instance => KeyBuilder;
+ }
+
protected class
NonGenericTestReferenceNavigationBuilder : TestReferenceNavigationBuilder
where TEntity : class
@@ -700,13 +717,13 @@ public override TestOwnedNavigationBuilder HasAnnotat
string annotation, object value)
=> Wrap(OwnedNavigationBuilder.HasAnnotation(annotation, value));
- public override TestKeyBuilder HasKey(Expression> keyExpression)
- => new TestKeyBuilder(
+ public override TestKeyBuilder HasKey(Expression> keyExpression)
+ => new NonGenericTestKeyBuilder(
OwnedNavigationBuilder.HasKey(
keyExpression.GetPropertyAccessList().Select(p => p.GetSimpleMemberName()).ToArray()));
- public override TestKeyBuilder HasKey(params string[] propertyNames)
- => new TestKeyBuilder(OwnedNavigationBuilder.HasKey(propertyNames));
+ public override TestKeyBuilder HasKey(params string[] propertyNames)
+ => new NonGenericTestKeyBuilder(OwnedNavigationBuilder.HasKey(propertyNames));
public override TestPropertyBuilder Property(string propertyName)
=> new NonGenericTestPropertyBuilder(OwnedNavigationBuilder.Property(propertyName));
diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs
index 314291556d7..9c51910ac41 100644
--- a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs
+++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs
@@ -182,10 +182,10 @@ public abstract TestEntityTypeBuilder HasBaseType()
where TBaseEntity : class;
public abstract TestEntityTypeBuilder HasBaseType(string baseEntityTypeName);
- public abstract TestKeyBuilder HasKey(Expression> keyExpression);
- public abstract TestKeyBuilder HasKey(params string[] propertyNames);
- public abstract TestKeyBuilder HasAlternateKey(Expression> keyExpression);
- public abstract TestKeyBuilder HasAlternateKey(params string[] propertyNames);
+ public abstract TestKeyBuilder HasKey(Expression> keyExpression);
+ public abstract TestKeyBuilder HasKey(params string[] propertyNames);
+ public abstract TestKeyBuilder HasAlternateKey(Expression> keyExpression);
+ public abstract TestKeyBuilder HasAlternateKey(params string[] propertyNames);
public abstract TestEntityTypeBuilder HasNoKey();
public abstract TestPropertyBuilder Property(
@@ -294,20 +294,11 @@ public abstract class TestOwnedEntityTypeBuilder
{
}
- public class TestKeyBuilder : IInfrastructure
+ public abstract class TestKeyBuilder
{
- public TestKeyBuilder(KeyBuilder keyBuilder)
- {
- KeyBuilder = keyBuilder;
- }
-
- private KeyBuilder KeyBuilder { get; }
- public IMutableKey Metadata => KeyBuilder.Metadata;
-
- public virtual TestKeyBuilder HasAnnotation(string annotation, object value)
- => new TestKeyBuilder(KeyBuilder.HasAnnotation(annotation, value));
+ public abstract IMutableKey Metadata { get; }
- KeyBuilder IInfrastructure.Instance => KeyBuilder;
+ public abstract TestKeyBuilder HasAnnotation(string annotation, object value);
}
public class TestIndexBuilder : IInfrastructure
@@ -508,8 +499,8 @@ public abstract class TestOwnedNavigationBuilder
public abstract TestOwnedNavigationBuilder HasAnnotation(
string annotation, object value);
- public abstract TestKeyBuilder HasKey(Expression> keyExpression);
- public abstract TestKeyBuilder HasKey(params string[] propertyNames);
+ public abstract TestKeyBuilder HasKey(Expression> keyExpression);
+ public abstract TestKeyBuilder HasKey(params string[] propertyNames);
public abstract TestPropertyBuilder Property(string propertyName);
public abstract TestPropertyBuilder IndexerProperty(string propertyName);