diff --git a/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs b/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs
index c94deac720f..8868fe52f08 100644
--- a/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs
+++ b/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs
@@ -161,6 +161,24 @@ public interface IConventionPropertyBuilder : IConventionPropertyBaseBuilder
/// if the maximum length of data allowed can be set for this property.
bool CanSetMaxLength(int? maxLength, bool fromDataAnnotation = false);
+ ///
+ /// Configures the value that will be used to determine if the property has been set or not. If the property is set to the
+ /// sentinel value, then it is considered not set. By default, the sentinel value is the CLR default value for the type of
+ /// the property.
+ ///
+ /// The sentinel value.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// The same builder instance if the configuration was applied, otherwise.
+ IConventionPropertyBuilder? HasSentinel(object? sentinel, bool fromDataAnnotation = false);
+
+ ///
+ /// Returns a value indicating whether the sentinel can be set for this property from the current configuration source.
+ ///
+ /// The sentinel value.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// if the sentinel can be set for this property.
+ bool CanSetSentinel(object? sentinel, bool fromDataAnnotation = false);
+
///
/// Configures whether the property as capable of persisting unicode characters.
///
diff --git a/src/EFCore/Metadata/Builders/PropertiesConfigurationBuilder.cs b/src/EFCore/Metadata/Builders/PropertiesConfigurationBuilder.cs
index 072223dec5b..ee4d38fce89 100644
--- a/src/EFCore/Metadata/Builders/PropertiesConfigurationBuilder.cs
+++ b/src/EFCore/Metadata/Builders/PropertiesConfigurationBuilder.cs
@@ -69,6 +69,20 @@ public virtual PropertiesConfigurationBuilder HaveMaxLength(int maxLength)
return this;
}
+ ///
+ /// Configures the value that will be used to determine if the property has been set or not. If the property is set to the
+ /// sentinel value, then it is considered not set. By default, the sentinel value is the CLR default value for the type of
+ /// the property.
+ ///
+ /// The sentinel value.
+ /// The same builder instance so that multiple configuration calls can be chained.
+ public virtual PropertiesConfigurationBuilder HaveSentinel(object? sentinel)
+ {
+ Configuration.SetSentinel(sentinel);
+
+ return this;
+ }
+
///
/// Configures the precision and scale of the property.
///
diff --git a/src/EFCore/Metadata/Builders/PropertyBuilder.cs b/src/EFCore/Metadata/Builders/PropertyBuilder.cs
index 3fc9f570b35..4f9155f3c9d 100644
--- a/src/EFCore/Metadata/Builders/PropertyBuilder.cs
+++ b/src/EFCore/Metadata/Builders/PropertyBuilder.cs
@@ -95,6 +95,20 @@ public virtual PropertyBuilder HasMaxLength(int maxLength)
return this;
}
+ ///
+ /// Configures the value that will be used to determine if the property has been set or not. If the property is set to the
+ /// sentinel value, then it is considered not set. By default, the sentinel value is the CLR default value for the type of
+ /// the property.
+ ///
+ /// The sentinel value.
+ /// The same builder instance if the configuration was applied, otherwise.
+ public virtual PropertyBuilder HasSentinel(object? sentinel)
+ {
+ Builder.HasSentinel(sentinel, ConfigurationSource.Explicit);
+
+ return this;
+ }
+
///
/// Configures the precision and scale of the property.
///
diff --git a/src/EFCore/Metadata/Builders/PropertyBuilder`.cs b/src/EFCore/Metadata/Builders/PropertyBuilder`.cs
index 031868f7be3..a4264488fc0 100644
--- a/src/EFCore/Metadata/Builders/PropertyBuilder`.cs
+++ b/src/EFCore/Metadata/Builders/PropertyBuilder`.cs
@@ -63,6 +63,16 @@ public PropertyBuilder(IMutableProperty property)
public new virtual PropertyBuilder HasMaxLength(int maxLength)
=> (PropertyBuilder)base.HasMaxLength(maxLength);
+ ///
+ /// Configures the value that will be used to determine if the property has been set or not. If the property is set to the
+ /// sentinel value, then it is considered not set. By default, the sentinel value is the CLR default value for the type of
+ /// the property.
+ ///
+ /// The sentinel value.
+ /// The same builder instance if the configuration was applied, otherwise.
+ public new virtual PropertyBuilder HasSentinel(object? sentinel)
+ => (PropertyBuilder)base.HasSentinel(sentinel);
+
///
/// Configures the precision and scale of the property.
///
diff --git a/src/EFCore/Metadata/Builders/TypeMappingConfigurationBuilder.cs b/src/EFCore/Metadata/Builders/TypeMappingConfigurationBuilder.cs
index 9d84aa09cf9..e050fb12a86 100644
--- a/src/EFCore/Metadata/Builders/TypeMappingConfigurationBuilder.cs
+++ b/src/EFCore/Metadata/Builders/TypeMappingConfigurationBuilder.cs
@@ -74,6 +74,20 @@ public virtual TypeMappingConfigurationBuilder HasMaxLength(int maxLength)
return this;
}
+ ///
+ /// Configures the value that will be used to determine if the property has been set or not. If the property is set to the
+ /// sentinel value, then it is considered not set. By default, the sentinel value is the CLR default value for the type of
+ /// the property.
+ ///
+ /// The sentinel value.
+ /// The same builder instance if the configuration was applied, otherwise.
+ public virtual TypeMappingConfigurationBuilder HasSentinel(object? sentinel)
+ {
+ Configuration.SetSentinel(sentinel);
+
+ return this;
+ }
+
///
/// Configures the precision and scale of the property.
///
diff --git a/src/EFCore/Metadata/Builders/TypeMappingConfigurationBuilder`.cs b/src/EFCore/Metadata/Builders/TypeMappingConfigurationBuilder`.cs
index 5d602145e71..67787f39ca8 100644
--- a/src/EFCore/Metadata/Builders/TypeMappingConfigurationBuilder`.cs
+++ b/src/EFCore/Metadata/Builders/TypeMappingConfigurationBuilder`.cs
@@ -53,6 +53,16 @@ public TypeMappingConfigurationBuilder(PropertyConfiguration scalar)
public new virtual TypeMappingConfigurationBuilder HasMaxLength(int maxLength)
=> (TypeMappingConfigurationBuilder)base.HasMaxLength(maxLength);
+ ///
+ /// Configures the value that will be used to determine if the property has been set or not. If the property is set to the
+ /// sentinel value, then it is considered not set. By default, the sentinel value is the CLR default value for the type of
+ /// the property.
+ ///
+ /// The sentinel value.
+ /// The same builder instance if the configuration was applied, otherwise.
+ public new virtual TypeMappingConfigurationBuilder HasSentinel(object? sentinel)
+ => (TypeMappingConfigurationBuilder)base.HasSentinel(sentinel);
+
///
/// Configures the precision and scale of the property.
///
diff --git a/src/EFCore/Metadata/Internal/CoreAnnotationNames.cs b/src/EFCore/Metadata/Internal/CoreAnnotationNames.cs
index dc238cab330..3df816e2e66 100644
--- a/src/EFCore/Metadata/Internal/CoreAnnotationNames.cs
+++ b/src/EFCore/Metadata/Internal/CoreAnnotationNames.cs
@@ -19,6 +19,14 @@ public static class CoreAnnotationNames
///
public const string MaxLength = "MaxLength";
+ ///
+ /// 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.
+ ///
+ public const string Sentinel = "Sentinel";
+
///
/// 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
@@ -317,6 +325,7 @@ public static class CoreAnnotationNames
public static readonly ISet AllNames = new HashSet
{
MaxLength,
+ Sentinel,
Precision,
Scale,
Unicode,
diff --git a/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs b/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs
index 4fe06855d01..a6d43af00c8 100644
--- a/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs
@@ -193,6 +193,34 @@ public virtual bool CanSetMaxLength(int? maxLength, ConfigurationSource? configu
=> configurationSource.Overrides(Metadata.GetMaxLengthConfigurationSource())
|| Metadata.GetMaxLength() == maxLength;
+ ///
+ /// 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.
+ ///
+ public virtual InternalPropertyBuilder? HasSentinel(object? sentinel, ConfigurationSource configurationSource)
+ {
+ if (CanSetSentinel(sentinel, configurationSource))
+ {
+ Metadata.SetSentinel(sentinel, configurationSource);
+
+ return this;
+ }
+
+ return null;
+ }
+
+ ///
+ /// 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.
+ ///
+ public virtual bool CanSetSentinel(object? sentinel, ConfigurationSource? configurationSource)
+ => configurationSource.Overrides(Metadata.GetSentinelConfigurationSource())
+ || Equals(Metadata.Sentinel, sentinel);
+
///
/// 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
@@ -1013,6 +1041,24 @@ bool IConventionPropertyBaseBuilder.CanSetPropertyAccessMode(PropertyAccessMode?
bool IConventionPropertyBuilder.CanSetMaxLength(int? maxLength, bool fromDataAnnotation)
=> CanSetMaxLength(maxLength, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+ ///
+ /// 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.
+ ///
+ IConventionPropertyBuilder? IConventionPropertyBuilder.HasSentinel(object? sentinel, bool fromDataAnnotation)
+ => HasSentinel(sentinel, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+
+ ///
+ /// 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.
+ ///
+ bool IConventionPropertyBuilder.CanSetSentinel(object? sentinel, bool fromDataAnnotation)
+ => CanSetSentinel(sentinel, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+
///
/// 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
diff --git a/src/EFCore/Metadata/Internal/PropertyConfiguration.cs b/src/EFCore/Metadata/Internal/PropertyConfiguration.cs
index 59f0541633a..f760e2c73a4 100644
--- a/src/EFCore/Metadata/Internal/PropertyConfiguration.cs
+++ b/src/EFCore/Metadata/Internal/PropertyConfiguration.cs
@@ -46,23 +46,21 @@ public virtual void Apply(IMutableProperty property)
{
case CoreAnnotationNames.MaxLength:
property.SetMaxLength((int?)annotation.Value);
-
+ break;
+ case CoreAnnotationNames.Sentinel:
+ property.Sentinel = annotation.Value;
break;
case CoreAnnotationNames.Unicode:
property.SetIsUnicode((bool?)annotation.Value);
-
break;
case CoreAnnotationNames.Precision:
property.SetPrecision((int?)annotation.Value);
-
break;
case CoreAnnotationNames.Scale:
property.SetScale((int?)annotation.Value);
-
break;
case CoreAnnotationNames.ProviderClrType:
property.SetProviderClrType((Type?)annotation.Value);
-
break;
case CoreAnnotationNames.ValueConverterType:
if (ClrType.UnwrapNullableType() == property.ClrType.UnwrapNullableType())
@@ -121,6 +119,24 @@ public virtual void SetMaxLength(int? maxLength)
this[CoreAnnotationNames.MaxLength] = maxLength;
}
+ ///
+ /// 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.
+ ///
+ public virtual int? GetSentinel()
+ => (int?)this[CoreAnnotationNames.Sentinel];
+
+ ///
+ /// 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.
+ ///
+ public virtual void SetSentinel(object? sentinel)
+ => this[CoreAnnotationNames.Sentinel] = sentinel;
+
///
/// 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
diff --git a/test/EFCore.SqlServer.FunctionalTests/GraphUpdates/GraphUpdatesSqlServerOwnedTest.cs b/test/EFCore.SqlServer.FunctionalTests/GraphUpdates/GraphUpdatesSqlServerOwnedTest.cs
index 859014b1a05..60390b6a4cd 100644
--- a/test/EFCore.SqlServer.FunctionalTests/GraphUpdates/GraphUpdatesSqlServerOwnedTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/GraphUpdates/GraphUpdatesSqlServerOwnedTest.cs
@@ -565,7 +565,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
modelBuilder.Entity(
b =>
{
- b.Property(e => e.IdUserState).HasDefaultValue(1).Metadata.Sentinel = 667;
+ b.Property(e => e.IdUserState).HasDefaultValue(1).HasSentinel(667);
b.HasOne(e => e.UserState).WithMany(e => e.Users).HasForeignKey(e => e.IdUserState);
});
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/GraphUpdates/GraphUpdatesSqlServerTestBase.cs b/test/EFCore.SqlServer.FunctionalTests/GraphUpdates/GraphUpdatesSqlServerTestBase.cs
index 46bbe702578..25f01f86e3a 100644
--- a/test/EFCore.SqlServer.FunctionalTests/GraphUpdates/GraphUpdatesSqlServerTestBase.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/GraphUpdates/GraphUpdatesSqlServerTestBase.cs
@@ -53,7 +53,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
modelBuilder.Entity(
b =>
{
- b.Property(e => e.IdUserState).HasDefaultValue(1).Metadata.Sentinel = 667;
+ b.Property(e => e.IdUserState).HasDefaultValue(1).HasSentinel(667);
b.HasOne(e => e.UserState).WithMany(e => e.Users).HasForeignKey(e => e.IdUserState);
});
diff --git a/test/EFCore.SqlServer.FunctionalTests/SqlServerSentinelValueGenerationScenariosTest.cs b/test/EFCore.SqlServer.FunctionalTests/SqlServerSentinelValueGenerationScenariosTest.cs
index 7eaeadff57b..4d910ff4201 100644
--- a/test/EFCore.SqlServer.FunctionalTests/SqlServerSentinelValueGenerationScenariosTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/SqlServerSentinelValueGenerationScenariosTest.cs
@@ -51,12 +51,12 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = IntSentinel;
- b.Property(e => e.Name).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.CreatedOn).Metadata.Sentinel = DateTimeSentinel;
- b.Property(e => e.GeometryCollection).Metadata.Sentinel = GeometryCollectionSentinel;
- b.Property(e => e.OtherId).Metadata.Sentinel = NullableIntSentinel;
- b.Property(e => e.NeedsConverter).Metadata.Sentinel = new NeedsConverter(IntSentinel);
+ b.Property(e => e.Id).HasSentinel(IntSentinel);
+ b.Property(e => e.Name).HasSentinel(StringSentinel);
+ b.Property(e => e.CreatedOn).HasSentinel(DateTimeSentinel);
+ b.Property(e => e.GeometryCollection).HasSentinel(GeometryCollectionSentinel);
+ b.Property(e => e.OtherId).HasSentinel(NullableIntSentinel);
+ b.Property(e => e.NeedsConverter).HasSentinel(new NeedsConverter(IntSentinel));
});
}
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/SqlServerValueGenerationScenariosTestBase.cs b/test/EFCore.SqlServer.FunctionalTests/SqlServerValueGenerationScenariosTestBase.cs
index 242dd36ba6c..fe4bce881df 100644
--- a/test/EFCore.SqlServer.FunctionalTests/SqlServerValueGenerationScenariosTestBase.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/SqlServerValueGenerationScenariosTestBase.cs
@@ -324,8 +324,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.Entity()
.Property(e => e.Id)
.HasDefaultValueSql("'i' + CAST((NEXT VALUE FOR MyStringSequence) AS VARCHAR(20))")
- .Metadata
- .Sentinel = _stringSentinel;
+ .HasSentinel(_stringSentinel);
}
}
@@ -424,7 +423,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.Entity()
.Property(e => e.Id)
.HasConversion()
- .Metadata.Sentinel = _uintSentinel;
+ .HasSentinel(_uintSentinel);
}
}
@@ -478,7 +477,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.Entity()
.Property(e => e.Id)
.ValueGeneratedOnAdd()
- .Metadata.Sentinel = _sentinel;
+ .HasSentinel(_sentinel);
}
}
@@ -539,7 +538,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.Entity()
.Property(e => e.Id)
.ValueGeneratedOnAdd()
- .Metadata.Sentinel = _sentinel;
+ .HasSentinel(_sentinel);
}
}
@@ -606,7 +605,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
: int.Parse(v),
v => v.ToString())
.ValueGeneratedOnAdd()
- .Metadata.Sentinel = _sentinel;
+ .HasSentinel(_sentinel);
}
}
@@ -693,7 +692,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.Entity()
.Property(e => e.Id)
.ValueGeneratedNever()
- .Metadata.Sentinel = _sentinel;
+ .HasSentinel(_sentinel);
}
}
@@ -898,11 +897,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = _intSentinel;
+ b.Property(e => e.Id).HasSentinel(_intSentinel);
- var property = b.Property(e => e.CreatedOn).HasDefaultValueSql("getdate()");
+ var property = b.Property(e => e.CreatedOn).HasDefaultValueSql("getdate()").HasSentinel(_dateTimeSentinel);
property.Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Throw);
- property.Metadata.Sentinel = _dateTimeSentinel;
});
}
}
@@ -962,15 +960,15 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = _intSentinel;
+ b.Property(e => e.Id).HasSentinel(_intSentinel);
var property = b.Property(e => e.FullName)
.HasComputedColumnSql("FirstName + ' ' + LastName")
+ .HasSentinel(_stringSentinel)
.Metadata;
property.SetBeforeSaveBehavior(PropertySaveBehavior.Throw);
property.SetAfterSaveBehavior(PropertySaveBehavior.Throw);
- property.Sentinel = _stringSentinel;
});
}
}
@@ -1063,15 +1061,15 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = _intSentinel;
+ b.Property(e => e.Id).HasSentinel(_intSentinel);
var property = modelBuilder.Entity()
.Property(e => e.FullName)
.HasComputedColumnSql("[dbo].[GetFullName]([FirstName], [LastName])")
+ .HasSentinel(_stringSentinel)
.Metadata;
property.SetAfterSaveBehavior(PropertySaveBehavior.Throw);
- property.Sentinel = _stringSentinel;
});
}
}
@@ -1316,8 +1314,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
eb =>
{
eb.HasAlternateKey(e => e.NotId);
- eb.Property(e => e.NotId).ValueGeneratedOnAdd().Metadata.Sentinel = _sentinel;
- eb.Property(e => e.Id).Metadata.Sentinel = _sentinel;
+ eb.Property(e => e.NotId).ValueGeneratedOnAdd().HasSentinel(_sentinel);
+ eb.Property(e => e.Id).HasSentinel(_sentinel);
});
}
}
@@ -1362,8 +1360,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = _sentinel;
- b.Property(e => e.NotId).ValueGeneratedOnAdd().Metadata.Sentinel = _sentinel;
+ b.Property(e => e.Id).HasSentinel(_sentinel);
+ b.Property(e => e.NotId).ValueGeneratedOnAdd().HasSentinel(_sentinel);
});
}
}
@@ -1426,8 +1424,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.Entity(
eb =>
{
- eb.Property(e => e.Id).HasDefaultValueSql("newsequentialid()").Metadata.Sentinel = _sentinel;
- eb.Property(e => e.NotId).HasDefaultValueSql("newsequentialid()").Metadata.Sentinel = _sentinel;
+ eb.Property(e => e.Id).HasDefaultValueSql("newsequentialid()").HasSentinel(_sentinel);
+ eb.Property(e => e.NotId).HasDefaultValueSql("newsequentialid()").HasSentinel(_sentinel);
});
}
}
@@ -1517,7 +1515,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.Entity()
.Property(e => e.Id)
.ValueGeneratedNever()
- .Metadata.Sentinel = _sentinel;
+ .HasSentinel(_sentinel);
}
}
@@ -1557,10 +1555,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
var property = modelBuilder
.Entity()
.Property(e => e.Id)
- .HasDefaultValueSql("next value for MySequence");
+ .HasDefaultValueSql("next value for MySequence")
+ .HasSentinel(_sentinel);
property.Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Throw);
- property.Metadata.Sentinel = _sentinel;
}
}
@@ -1715,11 +1713,11 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = _intSentinel;
+ b.Property(e => e.Id).HasSentinel(_intSentinel);
b.Property(e => e.Timestamp)
.ValueGeneratedOnAddOrUpdate()
.IsConcurrencyToken()
- .Metadata.Sentinel = _timestampSentinel;
+ .HasSentinel(_timestampSentinel);
});
}
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/StoreGeneratedSentinelSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/StoreGeneratedSentinelSqlServerTest.cs
index 3070c8c5837..6765ae7401f 100644
--- a/test/EFCore.SqlServer.FunctionalTests/StoreGeneratedSentinelSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/StoreGeneratedSentinelSqlServerTest.cs
@@ -102,223 +102,223 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = IntSentinel;
- b.Property(e => e.NotStoreGenerated).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.Identity).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.IdentityReadOnlyBeforeSave).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.IdentityReadOnlyAfterSave).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.AlwaysIdentity).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.AlwaysIdentityReadOnlyBeforeSave).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.AlwaysIdentityReadOnlyAfterSave).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.Computed).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.ComputedReadOnlyBeforeSave).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.ComputedReadOnlyAfterSave).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.AlwaysComputed).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.AlwaysComputedReadOnlyBeforeSave).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.AlwaysComputedReadOnlyAfterSave).Metadata.Sentinel = StringSentinel;
+ b.Property(e => e.Id).HasSentinel(IntSentinel);
+ b.Property(e => e.NotStoreGenerated).HasSentinel(StringSentinel);
+ b.Property(e => e.Identity).HasSentinel(StringSentinel);
+ b.Property(e => e.IdentityReadOnlyBeforeSave).HasSentinel(StringSentinel);
+ b.Property(e => e.IdentityReadOnlyAfterSave).HasSentinel(StringSentinel);
+ b.Property(e => e.AlwaysIdentity).HasSentinel(StringSentinel);
+ b.Property(e => e.AlwaysIdentityReadOnlyBeforeSave).HasSentinel(StringSentinel);
+ b.Property(e => e.AlwaysIdentityReadOnlyAfterSave).HasSentinel(StringSentinel);
+ b.Property(e => e.Computed).HasSentinel(StringSentinel);
+ b.Property(e => e.ComputedReadOnlyBeforeSave).HasSentinel(StringSentinel);
+ b.Property(e => e.ComputedReadOnlyAfterSave).HasSentinel(StringSentinel);
+ b.Property(e => e.AlwaysComputed).HasSentinel(StringSentinel);
+ b.Property(e => e.AlwaysComputedReadOnlyBeforeSave).HasSentinel(StringSentinel);
+ b.Property(e => e.AlwaysComputedReadOnlyAfterSave).HasSentinel(StringSentinel);
});
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = IntSentinel;
- b.Property(e => e.Never).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.NeverUseBeforeUseAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.NeverIgnoreBeforeUseAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.NeverThrowBeforeUseAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.NeverUseBeforeIgnoreAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.NeverIgnoreBeforeIgnoreAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.NeverThrowBeforeIgnoreAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.NeverUseBeforeThrowAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.NeverIgnoreBeforeThrowAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.NeverThrowBeforeThrowAfter).Metadata.Sentinel = StringSentinel;
-
- b.Property(e => e.OnAdd).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddUseBeforeUseAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddIgnoreBeforeUseAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddThrowBeforeUseAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddUseBeforeIgnoreAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddIgnoreBeforeIgnoreAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddThrowBeforeIgnoreAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddUseBeforeThrowAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddIgnoreBeforeThrowAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddThrowBeforeThrowAfter).Metadata.Sentinel = StringSentinel;
-
- b.Property(e => e.OnAddOrUpdate).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddOrUpdateUseBeforeUseAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddOrUpdateIgnoreBeforeUseAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddOrUpdateThrowBeforeUseAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddOrUpdateUseBeforeIgnoreAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddOrUpdateIgnoreBeforeIgnoreAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddOrUpdateThrowBeforeIgnoreAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddOrUpdateUseBeforeThrowAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddOrUpdateIgnoreBeforeThrowAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnAddOrUpdateThrowBeforeThrowAfter).Metadata.Sentinel = StringSentinel;
-
- b.Property(e => e.OnUpdate).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnUpdateUseBeforeUseAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnUpdateIgnoreBeforeUseAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnUpdateThrowBeforeUseAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnUpdateUseBeforeIgnoreAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnUpdateIgnoreBeforeIgnoreAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnUpdateThrowBeforeIgnoreAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnUpdateUseBeforeThrowAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnUpdateIgnoreBeforeThrowAfter).Metadata.Sentinel = StringSentinel;
- b.Property(e => e.OnUpdateThrowBeforeThrowAfter).Metadata.Sentinel = StringSentinel;
+ b.Property(e => e.Id).HasSentinel(IntSentinel);
+ b.Property(e => e.Never).HasSentinel(StringSentinel);
+ b.Property(e => e.NeverUseBeforeUseAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.NeverIgnoreBeforeUseAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.NeverThrowBeforeUseAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.NeverUseBeforeIgnoreAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.NeverIgnoreBeforeIgnoreAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.NeverThrowBeforeIgnoreAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.NeverUseBeforeThrowAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.NeverIgnoreBeforeThrowAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.NeverThrowBeforeThrowAfter).HasSentinel(StringSentinel);
+
+ b.Property(e => e.OnAdd).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddUseBeforeUseAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddIgnoreBeforeUseAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddThrowBeforeUseAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddUseBeforeIgnoreAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddIgnoreBeforeIgnoreAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddThrowBeforeIgnoreAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddUseBeforeThrowAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddIgnoreBeforeThrowAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddThrowBeforeThrowAfter).HasSentinel(StringSentinel);
+
+ b.Property(e => e.OnAddOrUpdate).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddOrUpdateUseBeforeUseAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddOrUpdateIgnoreBeforeUseAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddOrUpdateThrowBeforeUseAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddOrUpdateUseBeforeIgnoreAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddOrUpdateIgnoreBeforeIgnoreAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddOrUpdateThrowBeforeIgnoreAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddOrUpdateUseBeforeThrowAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddOrUpdateIgnoreBeforeThrowAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnAddOrUpdateThrowBeforeThrowAfter).HasSentinel(StringSentinel);
+
+ b.Property(e => e.OnUpdate).HasSentinel(StringSentinel);
+ b.Property(e => e.OnUpdateUseBeforeUseAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnUpdateIgnoreBeforeUseAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnUpdateThrowBeforeUseAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnUpdateUseBeforeIgnoreAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnUpdateIgnoreBeforeIgnoreAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnUpdateThrowBeforeIgnoreAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnUpdateUseBeforeThrowAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnUpdateIgnoreBeforeThrowAfter).HasSentinel(StringSentinel);
+ b.Property(e => e.OnUpdateThrowBeforeThrowAfter).HasSentinel(StringSentinel);
});
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = NullableIntSentinel;
- b.Property(e => e.NullableAsNonNullable).Metadata.Sentinel = NullableIntSentinel;
- b.Property(e => e.NonNullableAsNullable).Metadata.Sentinel = IntSentinel;
+ b.Property(e => e.Id).HasSentinel(NullableIntSentinel);
+ b.Property(e => e.NullableAsNonNullable).HasSentinel(NullableIntSentinel);
+ b.Property(e => e.NonNullableAsNullable).HasSentinel(IntSentinel);
});
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = NullableIntSentinel;
- b.Property(e => e.NullableBackedBoolTrueDefault).Metadata.Sentinel = NullableBoolSentinel;
- b.Property(e => e.NullableBackedIntNonZeroDefault).Metadata.Sentinel = NullableIntSentinel;
- b.Property(e => e.NullableBackedBoolFalseDefault).Metadata.Sentinel = NullableBoolSentinel;
- b.Property(e => e.NullableBackedIntZeroDefault).Metadata.Sentinel = NullableIntSentinel;
+ b.Property(e => e.Id).HasSentinel(NullableIntSentinel);
+ b.Property(e => e.NullableBackedBoolTrueDefault).HasSentinel(NullableBoolSentinel);
+ b.Property(e => e.NullableBackedIntNonZeroDefault).HasSentinel(NullableIntSentinel);
+ b.Property(e => e.NullableBackedBoolFalseDefault).HasSentinel(NullableBoolSentinel);
+ b.Property(e => e.NullableBackedIntZeroDefault).HasSentinel(NullableIntSentinel);
});
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = NullableIntSentinel;
- b.Property(e => e.NullableBackedBoolTrueDefault).Metadata.Sentinel = NullableBoolSentinel;
- b.Property(e => e.NullableBackedIntNonZeroDefault).Metadata.Sentinel = NullableIntSentinel;
- b.Property(e => e.NullableBackedBoolFalseDefault).Metadata.Sentinel = NullableBoolSentinel;
- b.Property(e => e.NullableBackedIntZeroDefault).Metadata.Sentinel = NullableIntSentinel;
+ b.Property(e => e.Id).HasSentinel(NullableIntSentinel);
+ b.Property(e => e.NullableBackedBoolTrueDefault).HasSentinel(NullableBoolSentinel);
+ b.Property(e => e.NullableBackedIntNonZeroDefault).HasSentinel(NullableIntSentinel);
+ b.Property(e => e.NullableBackedBoolFalseDefault).HasSentinel(NullableBoolSentinel);
+ b.Property(e => e.NullableBackedIntZeroDefault).HasSentinel(NullableIntSentinel);
});
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = IntSentinel;
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(IntSentinel);
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = IntSentinel;
- modelBuilder.Entity().Property(e => e.PrincipalId).Metadata.Sentinel = IntSentinel;
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(IntSentinel);
+ modelBuilder.Entity().Property(e => e.PrincipalId).HasSentinel(IntSentinel);
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = WrappedIntHiLoKeyClassSentinel;
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = WrappedIntHiLoKeyStructSentinel;
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = WrappedIntHiLoKeyRecordSentinel;
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(WrappedIntHiLoKeyClassSentinel);
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(WrappedIntHiLoKeyStructSentinel);
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(WrappedIntHiLoKeyRecordSentinel);
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = IntSentinel;
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = GuidSentinel;
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = GuidSentinel;
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = ShortSentinel;
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(IntSentinel);
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(GuidSentinel);
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(GuidSentinel);
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(ShortSentinel);
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = NullableIntSentinel;
- b.Property(e => e.Name).Metadata.Sentinel = StringSentinel;
+ b.Property(e => e.Id).HasSentinel(NullableIntSentinel);
+ b.Property(e => e.Name).HasSentinel(StringSentinel);
});
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = IntSentinel;
- b.Property(e => e.Name).Metadata.Sentinel = StringSentinel;
+ b.Property(e => e.Id).HasSentinel(IntSentinel);
+ b.Property(e => e.Name).HasSentinel(StringSentinel);
});
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = IntSentinel;
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = IntSentinel;
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(IntSentinel);
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(IntSentinel);
modelBuilder.Entity(
entity =>
{
- entity.Property(e => e.Id).Metadata.Sentinel = WrappedIntKeyClassSentinel;
- entity.Property(e => e.NonKey).Metadata.Sentinel = WrappedIntClassSentinel;
+ entity.Property(e => e.Id).HasSentinel(WrappedIntKeyClassSentinel);
+ entity.Property(e => e.NonKey).HasSentinel(WrappedIntClassSentinel);
});
modelBuilder.Entity(
entity =>
{
- entity.Property(e => e.Id).Metadata.Sentinel = WrappedIntKeyStructSentinel;
- entity.Property(e => e.NonKey).Metadata.Sentinel = WrappedIntStructSentinel;
+ entity.Property(e => e.Id).HasSentinel(WrappedIntKeyStructSentinel);
+ entity.Property(e => e.NonKey).HasSentinel(WrappedIntStructSentinel);
});
modelBuilder.Entity(
entity =>
{
- entity.Property(e => e.Id).Metadata.Sentinel = WrappedIntKeyRecordSentinel;
- entity.Property(e => e.NonKey).Metadata.Sentinel = WrappedIntRecordSentinel;
+ entity.Property(e => e.Id).HasSentinel(WrappedIntKeyRecordSentinel);
+ entity.Property(e => e.NonKey).HasSentinel(WrappedIntRecordSentinel);
});
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = LongSentinel;
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = LongToDecimalPrincipalSentinel;
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(LongSentinel);
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(LongToDecimalPrincipalSentinel);
modelBuilder.Entity(
entity =>
{
- entity.Property(e => e.Id).Metadata.Sentinel = WrappedGuidKeyClassSentinel;
- entity.Property(e => e.NonKey).Metadata.Sentinel = WrappedGuidClassSentinel;
+ entity.Property(e => e.Id).HasSentinel(WrappedGuidKeyClassSentinel);
+ entity.Property(e => e.NonKey).HasSentinel(WrappedGuidClassSentinel);
});
modelBuilder.Entity(
entity =>
{
- entity.Property(e => e.Id).Metadata.Sentinel = WrappedGuidKeyStructSentinel;
- entity.Property(e => e.NonKey).Metadata.Sentinel = WrappedGuidStructSentinel;
+ entity.Property(e => e.Id).HasSentinel(WrappedGuidKeyStructSentinel);
+ entity.Property(e => e.NonKey).HasSentinel(WrappedGuidStructSentinel);
});
modelBuilder.Entity(
entity =>
{
- entity.Property(e => e.Id).Metadata.Sentinel = WrappedGuidKeyRecordSentinel;
- entity.Property(e => e.NonKey).Metadata.Sentinel = WrappedGuidRecordSentinel;
+ entity.Property(e => e.Id).HasSentinel(WrappedGuidKeyRecordSentinel);
+ entity.Property(e => e.NonKey).HasSentinel(WrappedGuidRecordSentinel);
});
modelBuilder.Entity(
entity =>
{
- entity.Property(e => e.Id).Metadata.Sentinel = WrappedStringKeyClassSentinel;
- entity.Property(e => e.NonKey).Metadata.Sentinel = WrappedStringClassSentinel;
+ entity.Property(e => e.Id).HasSentinel(WrappedStringKeyClassSentinel);
+ entity.Property(e => e.NonKey).HasSentinel(WrappedStringClassSentinel);
});
modelBuilder.Entity(
entity =>
{
- entity.Property(e => e.Id).Metadata.Sentinel = WrappedStringKeyStructSentinel;
- entity.Property(e => e.NonKey).Metadata.Sentinel = WrappedStringStructSentinel;
+ entity.Property(e => e.Id).HasSentinel(WrappedStringKeyStructSentinel);
+ entity.Property(e => e.NonKey).HasSentinel(WrappedStringStructSentinel);
});
modelBuilder.Entity(
entity =>
{
- entity.Property(e => e.Id).Metadata.Sentinel = WrappedStringKeyRecordSentinel;
- entity.Property(e => e.NonKey).Metadata.Sentinel = WrappedStringRecordSentinel;
+ entity.Property(e => e.Id).HasSentinel(WrappedStringKeyRecordSentinel);
+ entity.Property(e => e.NonKey).HasSentinel(WrappedStringRecordSentinel);
});
modelBuilder.Entity(
entity =>
{
- entity.Property(e => e.Id).Metadata.Sentinel = WrappedUriKeyClassSentinel;
- entity.Property(e => e.NonKey).Metadata.Sentinel = WrappedUriClassSentinel;
+ entity.Property(e => e.Id).HasSentinel(WrappedUriKeyClassSentinel);
+ entity.Property(e => e.NonKey).HasSentinel(WrappedUriClassSentinel);
});
modelBuilder.Entity(
entity =>
{
- entity.Property(e => e.Id).Metadata.Sentinel = WrappedUriKeyStructSentinel;
- entity.Property(e => e.NonKey).Metadata.Sentinel = WrappedUriStructSentinel;
+ entity.Property(e => e.Id).HasSentinel(WrappedUriKeyStructSentinel);
+ entity.Property(e => e.NonKey).HasSentinel(WrappedUriStructSentinel);
});
modelBuilder.Entity(
entity =>
{
- entity.Property(e => e.Id).Metadata.Sentinel = WrappedUriKeyRecordSentinel;
- entity.Property(e => e.NonKey).Metadata.Sentinel = WrappedUriRecordSentinel;
+ entity.Property(e => e.Id).HasSentinel(WrappedUriKeyRecordSentinel);
+ entity.Property(e => e.NonKey).HasSentinel(WrappedUriRecordSentinel);
});
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = UriSentinel;
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(UriSentinel);
;
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = KeyEnumSentinel;
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(KeyEnumSentinel);
;
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = GuidAsStringSentinel;
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = StringAsGuidSentinel;
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(GuidAsStringSentinel);
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(StringAsGuidSentinel);
}
}
}
diff --git a/test/EFCore.Sqlite.FunctionalTests/GraphUpdates/GraphUpdatesSqliteTestBase.cs b/test/EFCore.Sqlite.FunctionalTests/GraphUpdates/GraphUpdatesSqliteTestBase.cs
index 04a2ee79623..6764c2e600c 100644
--- a/test/EFCore.Sqlite.FunctionalTests/GraphUpdates/GraphUpdatesSqliteTestBase.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/GraphUpdates/GraphUpdatesSqliteTestBase.cs
@@ -91,7 +91,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
modelBuilder.Entity(
b =>
{
- b.Property(e => e.IdUserState).HasDefaultValue(1).Metadata.Sentinel = 667;
+ b.Property(e => e.IdUserState).HasDefaultValue(1).HasSentinel(667);
b.HasOne(e => e.UserState).WithMany(e => e.Users).HasForeignKey(e => e.IdUserState);
});
diff --git a/test/EFCore.Tests/ChangeTracking/EntityEntryTest.cs b/test/EFCore.Tests/ChangeTracking/EntityEntryTest.cs
index 9bb5423ee53..2e39b0445be 100644
--- a/test/EFCore.Tests/ChangeTracking/EntityEntryTest.cs
+++ b/test/EFCore.Tests/ChangeTracking/EntityEntryTest.cs
@@ -157,13 +157,13 @@ protected internal override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity(
b =>
{
- b.Property(e => e.Id).Metadata.Sentinel = 667;
+ b.Property(e => e.Id).HasSentinel(667);
b.HasOne(e => e.Dependent)
.WithOne(e => e.Principal)
.HasForeignKey(e => e.Id);
});
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = 667;
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(667);
modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever();
@@ -181,7 +181,7 @@ protected internal override void OnModelCreating(ModelBuilder modelBuilder)
b =>
{
b.HasKey(e => new { e.Id1, e.Id2 });
- b.Property(e => e.Id2).ValueGeneratedOnAdd().Metadata.Sentinel = true;
+ b.Property(e => e.Id2).ValueGeneratedOnAdd().HasSentinel(true);
});
}
}
diff --git a/test/EFCore.Tests/DbContextServicesTest.cs b/test/EFCore.Tests/DbContextServicesTest.cs
index c1cc2763199..29fa6cae2f5 100644
--- a/test/EFCore.Tests/DbContextServicesTest.cs
+++ b/test/EFCore.Tests/DbContextServicesTest.cs
@@ -861,9 +861,9 @@ protected internal override void OnConfiguring(DbContextOptionsBuilder optionsBu
protected internal override void OnModelCreating(ModelBuilder modelBuilder)
{
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = IntSentinel;
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = IntSentinel;
- modelBuilder.Entity().Property(e => e.Id).Metadata.Sentinel = GuidSentinel;
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(IntSentinel);
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(IntSentinel);
+ modelBuilder.Entity().Property(e => e.Id).HasSentinel(GuidSentinel);
}
}
diff --git a/test/EFCore.Tests/Metadata/Internal/InternalPropertyBuilderTest.cs b/test/EFCore.Tests/Metadata/Internal/InternalPropertyBuilderTest.cs
index ce771033de9..0d6d73151b1 100644
--- a/test/EFCore.Tests/Metadata/Internal/InternalPropertyBuilderTest.cs
+++ b/test/EFCore.Tests/Metadata/Internal/InternalPropertyBuilderTest.cs
@@ -117,6 +117,37 @@ public void Can_only_override_existing_MaxLength_value_explicitly()
Assert.Equal(2, metadata.GetMaxLength().Value);
}
+ [ConditionalFact]
+ public void Can_only_override_lower_or_equal_source_sentinel()
+ {
+ var builder = CreateInternalPropertyBuilder();
+ var metadata = builder.Metadata;
+
+ Assert.NotNull(builder.HasSentinel(1, ConfigurationSource.DataAnnotation));
+ Assert.NotNull(builder.HasSentinel(2, ConfigurationSource.DataAnnotation));
+
+ Assert.Equal(2, metadata.Sentinel);
+
+ Assert.Null(builder.HasSentinel(1, ConfigurationSource.Convention));
+ Assert.Equal(2, metadata.Sentinel);
+ }
+
+ [ConditionalFact]
+ public void Can_only_override_existing_sentinel_value_explicitly()
+ {
+ var metadata = CreateProperty();
+ metadata.SetSentinel(1, ConfigurationSource.Explicit);
+ var builder = metadata.Builder;
+
+ Assert.NotNull(builder.HasSentinel(1, ConfigurationSource.DataAnnotation));
+ Assert.Null(builder.HasSentinel(2, ConfigurationSource.DataAnnotation));
+
+ Assert.Equal(1, metadata.Sentinel);
+
+ Assert.NotNull(builder.HasSentinel(2, ConfigurationSource.Explicit));
+ Assert.Equal(2, metadata.Sentinel);
+ }
+
[ConditionalFact]
public void Can_only_override_lower_or_equal_source_Precision()
{
diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs
index e00358d5610..136f94c24d5 100644
--- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs
+++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs
@@ -471,6 +471,9 @@ public override TestPropertyBuilder IsRequired(bool isRequired = true
public override TestPropertyBuilder HasMaxLength(int maxLength)
=> Wrap(PropertyBuilder.HasMaxLength(maxLength));
+ public override TestPropertyBuilder HasSentinel(object? sentinel)
+ => Wrap(PropertyBuilder.HasSentinel(sentinel));
+
public override TestPropertyBuilder HasPrecision(int precision)
=> Wrap(PropertyBuilder.HasPrecision(precision));
diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs
index e3e88baa4a3..5fa2ad3385d 100644
--- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs
+++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs
@@ -551,6 +551,9 @@ public override TestPropertyBuilder IsRequired(bool isRequired = true
public override TestPropertyBuilder HasMaxLength(int maxLength)
=> Wrap(PropertyBuilder.HasMaxLength(maxLength));
+ public override TestPropertyBuilder HasSentinel(object? sentinel)
+ => Wrap(PropertyBuilder.HasSentinel(sentinel));
+
public override TestPropertyBuilder HasPrecision(int precision)
=> Wrap(PropertyBuilder.HasPrecision(precision));
diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs
index 1e42c728396..80c7aaf02dc 100644
--- a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs
+++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs
@@ -374,6 +374,7 @@ public abstract class TestPropertyBuilder
public abstract TestPropertyBuilder HasAnnotation(string annotation, object? value);
public abstract TestPropertyBuilder IsRequired(bool isRequired = true);
public abstract TestPropertyBuilder HasMaxLength(int maxLength);
+ public abstract TestPropertyBuilder HasSentinel(object? sentinel);
public abstract TestPropertyBuilder HasPrecision(int precision);
public abstract TestPropertyBuilder HasPrecision(int precision, int scale);
public abstract TestPropertyBuilder IsUnicode(bool unicode = true);
diff --git a/test/EFCore.Tests/ModelBuilding/NonRelationshipTestBase.cs b/test/EFCore.Tests/ModelBuilding/NonRelationshipTestBase.cs
index ea60bd5b12f..edadba300ea 100644
--- a/test/EFCore.Tests/ModelBuilding/NonRelationshipTestBase.cs
+++ b/test/EFCore.Tests/ModelBuilding/NonRelationshipTestBase.cs
@@ -1437,6 +1437,65 @@ public virtual void Can_set_max_length_for_property_type()
Assert.Equal(100, entityType.FindProperty("Bottom").GetMaxLength());
}
+ [ConditionalFact]
+ public virtual void Can_set_sentinel_for_properties()
+ {
+ var modelBuilder = CreateModelBuilder();
+
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property(e => e.Up).HasSentinel(1);
+ b.Property(e => e.Down).HasSentinel("100");
+ b.Property("Charm").HasSentinel(-1);
+ b.Property("Strange").HasSentinel("-1");
+ b.Property("Top").HasSentinel(77);
+ b.Property("Bottom").HasSentinel("100");
+ });
+
+ var model = modelBuilder.FinalizeModel();
+ var entityType = model.FindEntityType(typeof(Quarks))!;
+
+ Assert.Equal(0, entityType.FindProperty(Customer.IdProperty.Name)!.Sentinel);
+ Assert.Equal(1, entityType.FindProperty("Up")!.Sentinel);
+ Assert.Equal("100", entityType.FindProperty("Down")!.Sentinel);
+ Assert.Equal(-1, entityType.FindProperty("Charm")!.Sentinel);
+ Assert.Equal("-1", entityType.FindProperty("Strange")!.Sentinel);
+ Assert.Equal(77, entityType.FindProperty("Top")!.Sentinel);
+ Assert.Equal("100", entityType.FindProperty("Bottom")!.Sentinel);
+ }
+
+ [ConditionalFact]
+ public virtual void Can_set_sentinel_for_property_type()
+ {
+ var modelBuilder = CreateModelBuilder(
+ c =>
+ {
+ c.Properties().HaveSentinel(-1);
+ c.Properties().HaveSentinel("100");
+ });
+
+ modelBuilder.Entity(
+ b =>
+ {
+ b.Property("Charm");
+ b.Property("Strange");
+ b.Property("Top");
+ b.Property("Bottom");
+ });
+
+ var model = modelBuilder.FinalizeModel();
+ var entityType = model.FindEntityType(typeof(Quarks))!;
+
+ Assert.Equal(-1, entityType.FindProperty(Customer.IdProperty.Name)!.Sentinel);
+ Assert.Equal(-1, entityType.FindProperty("Up")!.Sentinel);
+ Assert.Equal("100", entityType.FindProperty("Down")!.Sentinel);
+ Assert.Equal(-1, entityType.FindProperty("Charm")!.Sentinel);
+ Assert.Equal("100", entityType.FindProperty("Strange")!.Sentinel);
+ Assert.Equal(-1, entityType.FindProperty("Top")!.Sentinel);
+ Assert.Equal("100", entityType.FindProperty("Bottom")!.Sentinel);
+ }
+
[ConditionalFact]
public virtual void Can_set_unbounded_max_length_for_property_type()
{
@@ -1825,6 +1884,7 @@ public virtual void PropertyBuilder_methods_can_be_chained()
.ValueGeneratedOnUpdate()
.IsUnicode()
.HasMaxLength(100)
+ .HasSentinel(null)
.HasPrecision(10, 1)
.HasValueGenerator()
.HasValueGenerator(typeof(CustomValueGenerator))