diff --git a/src/EFCore/Metadata/Builders/IConventionNavigationBuilder.cs b/src/EFCore/Metadata/Builders/IConventionNavigationBuilder.cs
index 39db36bf639..16cae240379 100644
--- a/src/EFCore/Metadata/Builders/IConventionNavigationBuilder.cs
+++ b/src/EFCore/Metadata/Builders/IConventionNavigationBuilder.cs
@@ -15,22 +15,13 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Builders
/// not used in application code.
///
///
- public interface IConventionNavigationBuilder : IConventionAnnotatableBuilder
+ public interface IConventionNavigationBuilder : IConventionPropertyBaseBuilder
{
///
/// Gets the navigation being configured.
///
new IConventionNavigation Metadata { get; }
- ///
- /// Returns a value indicating whether the backing field can be set for this navigation
- /// from the given configuration source.
- ///
- /// The field name.
- /// Indicates whether the configuration was specified using a data annotation.
- /// if the backing field can be set for this property.
- bool CanSetField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
-
///
/// Sets the backing field to use for this navigation.
///
@@ -40,16 +31,7 @@ public interface IConventionNavigationBuilder : IConventionAnnotatableBuilder
/// The same builder instance if the configuration was applied,
/// otherwise.
///
- IConventionNavigationBuilder HasField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
-
- ///
- /// Returns a value indicating whether the backing field can be set for this navigation
- /// from the given configuration source.
- ///
- /// The field.
- /// Indicates whether the configuration was specified using a data annotation.
- /// if the backing field can be set for this property.
- bool CanSetField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
+ new IConventionNavigationBuilder HasField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
///
/// Sets the backing field to use for this navigation.
@@ -60,16 +42,7 @@ public interface IConventionNavigationBuilder : IConventionAnnotatableBuilder
/// The same builder instance if the configuration was applied,
/// otherwise.
///
- IConventionNavigationBuilder HasField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
-
- ///
- /// Returns a value indicating whether the can be set for this navigation
- /// from the current configuration source.
- ///
- /// The to use for this navigation.
- /// Indicates whether the configuration was specified using a data annotation.
- /// if the can be set for this navigation.
- bool CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);
+ new IConventionNavigationBuilder HasField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
///
/// Sets the to use for this navigation.
@@ -80,7 +53,7 @@ public interface IConventionNavigationBuilder : IConventionAnnotatableBuilder
/// The same builder instance if the configuration was applied,
/// otherwise.
///
- IConventionNavigationBuilder UsePropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);
+ new IConventionNavigationBuilder UsePropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);
///
/// Returns a value indicating whether this navigation can be configured to be automatically included in a query
diff --git a/src/EFCore/Metadata/Builders/IConventionPropertyBaseBuilder.cs b/src/EFCore/Metadata/Builders/IConventionPropertyBaseBuilder.cs
new file mode 100644
index 00000000000..c614176b8ee
--- /dev/null
+++ b/src/EFCore/Metadata/Builders/IConventionPropertyBaseBuilder.cs
@@ -0,0 +1,85 @@
+// 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 System.Reflection;
+using JetBrains.Annotations;
+
+namespace Microsoft.EntityFrameworkCore.Metadata.Builders
+{
+ ///
+ ///
+ /// Provides a simple API surface for configuring an from conventions.
+ ///
+ ///
+ /// This interface is typically used by database providers (and other extensions). It is generally
+ /// not used in application code.
+ ///
+ ///
+ public interface IConventionPropertyBaseBuilder : IConventionAnnotatableBuilder
+ {
+ ///
+ /// Gets the property-like object being configured.
+ ///
+ new IConventionPropertyBase Metadata { get; }
+
+ ///
+ /// Sets the backing field to use for this property-like object.
+ ///
+ /// The field name.
+ /// Indicates whether the configuration was specified using a data annotation.
+ ///
+ /// The same builder instance if the configuration was applied,
+ /// otherwise.
+ ///
+ IConventionPropertyBaseBuilder HasField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
+
+ ///
+ /// Sets the backing field to use for this property-like object.
+ ///
+ /// The field.
+ /// Indicates whether the configuration was specified using a data annotation.
+ ///
+ /// The same builder instance if the configuration was applied,
+ /// otherwise.
+ ///
+ IConventionPropertyBaseBuilder HasField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
+
+ ///
+ /// Returns a value indicating whether the backing field can be set for this property-like object
+ /// from the current configuration source.
+ ///
+ /// The field name.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// if the backing field can be set for this property-like object.
+ bool CanSetField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
+
+ ///
+ /// Returns a value indicating whether the backing field can be set for this property-like object
+ /// from the current configuration source.
+ ///
+ /// The field.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// if the backing field can be set for this property-like object.
+ bool CanSetField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
+
+ ///
+ /// Sets the to use for this property-like object.
+ ///
+ /// The to use for this property-like object.
+ /// Indicates whether the configuration was specified using a data annotation.
+ ///
+ /// The same builder instance if the configuration was applied,
+ /// otherwise.
+ ///
+ IConventionPropertyBaseBuilder UsePropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);
+
+ ///
+ /// Returns a value indicating whether the can be set for this property-like object
+ /// from the current configuration source.
+ ///
+ /// The to use for this property-like object.
+ /// Indicates whether the configuration was specified using a data annotation.
+ /// if the can be set for this property-like object.
+ bool CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);
+ }
+}
diff --git a/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs b/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs
index 7752f977fa3..fef9d241c7e 100644
--- a/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs
+++ b/src/EFCore/Metadata/Builders/IConventionPropertyBuilder.cs
@@ -19,7 +19,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Builders
/// not used in application code.
///
///
- public interface IConventionPropertyBuilder : IConventionAnnotatableBuilder
+ public interface IConventionPropertyBuilder : IConventionPropertyBaseBuilder
{
///
/// Gets the property being configured.
@@ -117,7 +117,7 @@ public interface IConventionPropertyBuilder : IConventionAnnotatableBuilder
/// The same builder instance if the configuration was applied,
/// otherwise.
///
- IConventionPropertyBuilder HasField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
+ new IConventionPropertyBuilder HasField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
///
/// Sets the backing field to use for this property.
@@ -128,25 +128,7 @@ public interface IConventionPropertyBuilder : IConventionAnnotatableBuilder
/// The same builder instance if the configuration was applied,
/// otherwise.
///
- IConventionPropertyBuilder HasField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
-
- ///
- /// Returns a value indicating whether the backing field can be set for this property
- /// from the current configuration source.
- ///
- /// The field name.
- /// Indicates whether the configuration was specified using a data annotation.
- /// if the backing field can be set for this property.
- bool CanSetField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
-
- ///
- /// Returns a value indicating whether the backing field can be set for this property
- /// from the current configuration source.
- ///
- /// The field.
- /// Indicates whether the configuration was specified using a data annotation.
- /// if the backing field can be set for this property.
- bool CanSetField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
+ new IConventionPropertyBuilder HasField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
///
/// Sets the to use for this property.
@@ -157,16 +139,7 @@ public interface IConventionPropertyBuilder : IConventionAnnotatableBuilder
/// The same builder instance if the configuration was applied,
/// otherwise.
///
- IConventionPropertyBuilder UsePropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);
-
- ///
- /// Returns a value indicating whether the can be set for this property
- /// from the current configuration source.
- ///
- /// The to use for this property.
- /// Indicates whether the configuration was specified using a data annotation.
- /// if the can be set for this property.
- bool CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);
+ new IConventionPropertyBuilder UsePropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);
///
/// Configures the maximum length of data that can be stored in this property.
diff --git a/src/EFCore/Metadata/Builders/IConventionServicePropertyBuilder.cs b/src/EFCore/Metadata/Builders/IConventionServicePropertyBuilder.cs
index 309787af13c..5894004a12b 100644
--- a/src/EFCore/Metadata/Builders/IConventionServicePropertyBuilder.cs
+++ b/src/EFCore/Metadata/Builders/IConventionServicePropertyBuilder.cs
@@ -15,7 +15,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Builders
/// not used in application code.
///
///
- public interface IConventionServicePropertyBuilder : IConventionAnnotatableBuilder
+ public interface IConventionServicePropertyBuilder : IConventionPropertyBaseBuilder
{
///
/// Gets the service property being configured.
@@ -31,7 +31,7 @@ public interface IConventionServicePropertyBuilder : IConventionAnnotatableBuild
/// The same builder instance if the configuration was applied,
/// otherwise.
///
- IConventionServicePropertyBuilder HasField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
+ new IConventionServicePropertyBuilder HasField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
///
/// Sets the backing field to use for this property.
@@ -42,25 +42,18 @@ public interface IConventionServicePropertyBuilder : IConventionAnnotatableBuild
/// The same builder instance if the configuration was applied,
/// otherwise.
///
- IConventionServicePropertyBuilder HasField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
+ new IConventionServicePropertyBuilder HasField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
///
- /// Returns a value indicating whether the backing field can be set for this property
- /// from the current configuration source.
- ///
- /// The field name.
- /// Indicates whether the configuration was specified using a data annotation.
- /// if the backing field can be set for this property.
- bool CanSetField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
-
- ///
- /// Returns a value indicating whether the backing field can be set for this property
- /// from the current configuration source.
+ /// Sets the to use for this property.
///
- /// The field.
+ /// The to use for this property.
/// Indicates whether the configuration was specified using a data annotation.
- /// if the backing field can be set for this property.
- bool CanSetField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
+ ///
+ /// The same builder instance if the configuration was applied,
+ /// otherwise.
+ ///
+ new IConventionServicePropertyBuilder UsePropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);
///
/// Sets the for this property.
diff --git a/src/EFCore/Metadata/Builders/IConventionSkipNavigationBuilder.cs b/src/EFCore/Metadata/Builders/IConventionSkipNavigationBuilder.cs
index 03b220e78c9..43654470e6b 100644
--- a/src/EFCore/Metadata/Builders/IConventionSkipNavigationBuilder.cs
+++ b/src/EFCore/Metadata/Builders/IConventionSkipNavigationBuilder.cs
@@ -15,7 +15,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Builders
/// not used in application code.
///
///
- public interface IConventionSkipNavigationBuilder : IConventionAnnotatableBuilder
+ public interface IConventionSkipNavigationBuilder : IConventionPropertyBaseBuilder
{
///
/// Gets the navigation property being configured.
@@ -31,7 +31,7 @@ public interface IConventionSkipNavigationBuilder : IConventionAnnotatableBuilde
/// The same builder instance if the configuration was applied,
/// otherwise.
///
- IConventionSkipNavigationBuilder HasField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
+ new IConventionSkipNavigationBuilder HasField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
///
/// Sets the backing field to use for this navigation.
@@ -42,25 +42,7 @@ public interface IConventionSkipNavigationBuilder : IConventionAnnotatableBuilde
/// The same builder instance if the configuration was applied,
/// otherwise.
///
- IConventionSkipNavigationBuilder HasField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
-
- ///
- /// Returns a value indicating whether the backing field can be set for this navigation
- /// from the given configuration source.
- ///
- /// The field name.
- /// Indicates whether the configuration was specified using a data annotation.
- /// if the backing field can be set for this property.
- bool CanSetField([CanBeNull] string fieldName, bool fromDataAnnotation = false);
-
- ///
- /// Returns a value indicating whether the backing field can be set for this navigation
- /// from the given configuration source.
- ///
- /// The field.
- /// Indicates whether the configuration was specified using a data annotation.
- /// if the backing field can be set for this property.
- bool CanSetField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
+ new IConventionSkipNavigationBuilder HasField([CanBeNull] FieldInfo fieldInfo, bool fromDataAnnotation = false);
///
/// Sets the to use for this navigation.
@@ -71,16 +53,7 @@ public interface IConventionSkipNavigationBuilder : IConventionAnnotatableBuilde
/// The same builder instance if the configuration was applied,
/// otherwise.
///
- IConventionSkipNavigationBuilder UsePropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);
-
- ///
- /// Returns a value indicating whether the can be set for this navigation
- /// from the given configuration source.
- ///
- /// The to use for this navigation.
- /// Indicates whether the configuration was specified using a data annotation.
- /// if the can be set for this property.
- bool CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);
+ new IConventionSkipNavigationBuilder UsePropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation = false);
///
/// Sets the foreign key.
diff --git a/src/EFCore/Metadata/Conventions/BackingFieldConvention.cs b/src/EFCore/Metadata/Conventions/BackingFieldConvention.cs
index 31ffe0372f0..56736df6059 100644
--- a/src/EFCore/Metadata/Conventions/BackingFieldConvention.cs
+++ b/src/EFCore/Metadata/Conventions/BackingFieldConvention.cs
@@ -57,11 +57,7 @@ public virtual void ProcessPropertyAdded(
IConventionPropertyBuilder propertyBuilder,
IConventionContext context)
{
- var field = GetFieldToSet(propertyBuilder.Metadata);
- if (field != null)
- {
- propertyBuilder.HasField(field);
- }
+ DiscoverField(propertyBuilder);
}
///
@@ -69,11 +65,49 @@ public virtual void ProcessNavigationAdded(
IConventionNavigationBuilder navigationBuilder,
IConventionContext context)
{
- var navigation = navigationBuilder.Metadata;
- var field = GetFieldToSet(navigation);
- if (field != null)
+ DiscoverField(navigationBuilder);
+ }
+
+ ///
+ public virtual void ProcessSkipNavigationAdded(
+ IConventionSkipNavigationBuilder skipNavigationBuilder,
+ IConventionContext context)
+ {
+ DiscoverField(skipNavigationBuilder);
+ }
+
+ ///
+ public virtual void ProcessModelFinalizing(
+ IConventionModelBuilder modelBuilder,
+ IConventionContext context)
+ {
+ foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
{
- navigation.Builder.HasField(field);
+ foreach (var property in entityType.GetDeclaredProperties())
+ {
+ var ambiguousField = property.FindAnnotation(CoreAnnotationNames.AmbiguousField);
+ if (ambiguousField != null)
+ {
+ if (property.GetFieldName() == null)
+ {
+ throw new InvalidOperationException((string)ambiguousField.Value);
+ }
+
+ property.RemoveAnnotation(CoreAnnotationNames.AmbiguousField);
+ }
+ }
+ }
+ }
+
+ private void DiscoverField(IConventionPropertyBaseBuilder conventionPropertyBaseBuilder)
+ {
+ if (ConfigurationSource.Convention.Overrides(conventionPropertyBaseBuilder.Metadata.GetFieldInfoConfigurationSource()))
+ {
+ var field = GetFieldToSet(conventionPropertyBaseBuilder.Metadata);
+ if (field != null)
+ {
+ conventionPropertyBaseBuilder.HasField(field);
+ }
}
}
@@ -239,40 +273,5 @@ private static int PrefixBinarySearch(KeyValuePair[] array, string
right = middle - 1;
}
}
-
- ///
- public virtual void ProcessModelFinalizing(
- IConventionModelBuilder modelBuilder,
- IConventionContext context)
- {
- foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
- {
- foreach (var property in entityType.GetDeclaredProperties())
- {
- var ambiguousField = property.FindAnnotation(CoreAnnotationNames.AmbiguousField);
- if (ambiguousField != null)
- {
- if (property.GetFieldName() == null)
- {
- throw new InvalidOperationException((string)ambiguousField.Value);
- }
-
- property.RemoveAnnotation(CoreAnnotationNames.AmbiguousField);
- }
- }
- }
- }
-
- ///
- public virtual void ProcessSkipNavigationAdded(
- IConventionSkipNavigationBuilder skipNavigationBuilder,
- IConventionContext context)
- {
- var field = GetFieldToSet(skipNavigationBuilder.Metadata);
- if (field != null)
- {
- skipNavigationBuilder.HasField(field);
- }
- }
}
}
diff --git a/src/EFCore/Metadata/Conventions/Infrastructure/ProviderConventionSetBuilder.cs b/src/EFCore/Metadata/Conventions/Infrastructure/ProviderConventionSetBuilder.cs
index 7ccbb2e18bf..57c411a4942 100644
--- a/src/EFCore/Metadata/Conventions/Infrastructure/ProviderConventionSetBuilder.cs
+++ b/src/EFCore/Metadata/Conventions/Infrastructure/ProviderConventionSetBuilder.cs
@@ -114,6 +114,7 @@ public virtual ConventionSet CreateConventionSet()
var timestampAttributeConvention = new TimestampAttributeConvention(Dependencies);
var backingFieldAttributeConvention = new BackingFieldAttributeConvention(Dependencies);
+ conventionSet.PropertyAddedConventions.Add(backingFieldAttributeConvention);
conventionSet.PropertyAddedConventions.Add(backingFieldConvention);
conventionSet.PropertyAddedConventions.Add(concurrencyCheckAttributeConvention);
conventionSet.PropertyAddedConventions.Add(databaseGeneratedAttributeConvention);
@@ -122,7 +123,6 @@ public virtual ConventionSet CreateConventionSet()
conventionSet.PropertyAddedConventions.Add(maxLengthAttributeConvention);
conventionSet.PropertyAddedConventions.Add(stringLengthAttributeConvention);
conventionSet.PropertyAddedConventions.Add(timestampAttributeConvention);
- conventionSet.PropertyAddedConventions.Add(backingFieldAttributeConvention);
conventionSet.PropertyAddedConventions.Add(keyAttributeConvention);
conventionSet.PropertyAddedConventions.Add(keyDiscoveryConvention);
conventionSet.PropertyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention);
@@ -170,8 +170,8 @@ public virtual ConventionSet CreateConventionSet()
var requiredNavigationAttributeConvention = new RequiredNavigationAttributeConvention(Dependencies);
var nonNullableNavigationConvention = new NonNullableNavigationConvention(Dependencies);
- conventionSet.NavigationAddedConventions.Add(backingFieldConvention);
conventionSet.NavigationAddedConventions.Add(new NavigationBackingFieldAttributeConvention(Dependencies));
+ conventionSet.NavigationAddedConventions.Add(backingFieldConvention);
conventionSet.NavigationAddedConventions.Add(requiredNavigationAttributeConvention);
conventionSet.NavigationAddedConventions.Add(nonNullableNavigationConvention);
conventionSet.NavigationAddedConventions.Add(inversePropertyAttributeConvention);
@@ -180,6 +180,7 @@ public virtual ConventionSet CreateConventionSet()
conventionSet.NavigationAddedConventions.Add(foreignKeyAttributeConvention);
var manyToManyJoinEntityTypeConvention = new ManyToManyJoinEntityTypeConvention(Dependencies);
+ conventionSet.SkipNavigationAddedConventions.Add(new SkipNavigationBackingFieldAttributeConvention(Dependencies));
conventionSet.SkipNavigationAddedConventions.Add(backingFieldConvention);
conventionSet.SkipNavigationAddedConventions.Add(manyToManyJoinEntityTypeConvention);
diff --git a/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs b/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs
index 44a098f64db..43b5cf836e0 100644
--- a/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs
+++ b/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs
@@ -24,6 +24,7 @@ public abstract class NavigationAttributeConventionBase :
IEntityTypeBaseTypeChangedConvention,
IEntityTypeMemberIgnoredConvention,
INavigationAddedConvention,
+ ISkipNavigationAddedConvention,
IForeignKeyPrincipalEndChangedConvention
where TAttribute : Attribute
{
@@ -171,6 +172,23 @@ public virtual void ProcessNavigationAdded(
}
}
+ ///
+ public virtual void ProcessSkipNavigationAdded(
+ IConventionSkipNavigationBuilder skipNavigationBuilder,
+ IConventionContext context)
+ {
+ var skipNavigation = skipNavigationBuilder.Metadata;
+ var attributes = GetAttributes(skipNavigation.DeclaringEntityType, skipNavigation);
+ foreach (var attribute in attributes)
+ {
+ ProcessSkipNavigationAdded(skipNavigationBuilder, attribute, context);
+ if (((IReadableConventionContext)context).ShouldStopProcessing())
+ {
+ break;
+ }
+ }
+ }
+
///
public virtual void ProcessForeignKeyPrincipalEndChanged(
IConventionForeignKeyBuilder relationshipBuilder,
@@ -234,8 +252,24 @@ private Type FindCandidateNavigationWithAttributePropertyType([NotNull] Property
protected static IEnumerable GetAttributes(
[NotNull] IConventionEntityType entityType, [NotNull] IConventionNavigation navigation)
where TCustomAttribute : Attribute
+ => GetAttributes(entityType, navigation.GetIdentifyingMemberInfo());
+
+ ///
+ /// Returns the attributes applied to the given skip navigation.
+ ///
+ /// The entity type.
+ /// The skip navigation.
+ /// The attribute type to look for.
+ /// The attributes applied to the given skip navigation.
+ protected static IEnumerable GetAttributes(
+ [NotNull] IConventionEntityType entityType, [NotNull] IConventionSkipNavigation skipNavigation)
+ where TCustomAttribute : Attribute
+ => GetAttributes(entityType, skipNavigation.GetIdentifyingMemberInfo());
+
+ private static IEnumerable GetAttributes(
+ [NotNull] IConventionEntityType entityType, [NotNull] MemberInfo memberInfo)
+ where TCustomAttribute : Attribute
{
- var memberInfo = navigation.GetIdentifyingMemberInfo();
if (!entityType.HasClrType()
|| memberInfo == null)
{
@@ -313,6 +347,18 @@ public virtual void ProcessNavigationAdded(
[NotNull] IConventionContext context)
=> throw new NotImplementedException();
+ ///
+ /// Called after a skip navigation property that has an attribute is added to an entity type.
+ ///
+ /// The builder for the navigation.
+ /// The attribute.
+ /// Additional information associated with convention execution.
+ public virtual void ProcessSkipNavigationAdded(
+ [NotNull] IConventionSkipNavigationBuilder skipNavigationBuilder,
+ [NotNull] TAttribute attribute,
+ [NotNull] IConventionContext context)
+ => throw new NotImplementedException();
+
///
/// Called after a navigation property that has an attribute is ignored.
///
diff --git a/src/EFCore/Metadata/Conventions/SkipNavigationBackingFieldAttributeConvention.cs b/src/EFCore/Metadata/Conventions/SkipNavigationBackingFieldAttributeConvention.cs
new file mode 100644
index 00000000000..532c71305a2
--- /dev/null
+++ b/src/EFCore/Metadata/Conventions/SkipNavigationBackingFieldAttributeConvention.cs
@@ -0,0 +1,34 @@
+// 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.Metadata.Builders;
+using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
+
+namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
+{
+ ///
+ /// A convention that configures a skip navigation property as having a backing field
+ /// based on the attribute.
+ ///
+ public class SkipNavigationBackingFieldAttributeConvention : NavigationAttributeConventionBase
+ {
+ ///
+ /// Creates a new instance of .
+ ///
+ /// Parameter object containing dependencies for this convention.
+ public SkipNavigationBackingFieldAttributeConvention([NotNull] ProviderConventionSetBuilderDependencies dependencies)
+ : base(dependencies)
+ {
+ }
+
+ ///
+ public override void ProcessSkipNavigationAdded(
+ IConventionSkipNavigationBuilder skipNavigationBuilder,
+ BackingFieldAttribute attribute,
+ IConventionContext context)
+ {
+ skipNavigationBuilder.HasField(attribute.Name, fromDataAnnotation: true);
+ }
+ }
+}
diff --git a/src/EFCore/Metadata/Internal/InternalNavigationBuilder.cs b/src/EFCore/Metadata/Internal/InternalNavigationBuilder.cs
index 4212cd0493e..fd270bf0a08 100644
--- a/src/EFCore/Metadata/Internal/InternalNavigationBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalNavigationBuilder.cs
@@ -87,6 +87,12 @@ public virtual InternalNavigationBuilder AutoInclude(bool? autoInclude, Configur
return null;
}
+ IConventionPropertyBase IConventionPropertyBaseBuilder.Metadata
+ {
+ [DebuggerStepThrough]
+ get => Metadata;
+ }
+
IConventionNavigation IConventionNavigationBuilder.Metadata
{
[DebuggerStepThrough]
@@ -95,10 +101,17 @@ IConventionNavigation IConventionNavigationBuilder.Metadata
///
[DebuggerStepThrough]
- bool IConventionNavigationBuilder.CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation)
+ bool IConventionPropertyBaseBuilder.CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation)
=> CanSetPropertyAccessMode(
propertyAccessMode, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+ ///
+ [DebuggerStepThrough]
+ IConventionPropertyBaseBuilder IConventionPropertyBaseBuilder.UsePropertyAccessMode(
+ PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation)
+ => UsePropertyAccessMode(
+ propertyAccessMode, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+
///
[DebuggerStepThrough]
IConventionNavigationBuilder IConventionNavigationBuilder.UsePropertyAccessMode(
@@ -108,11 +121,18 @@ IConventionNavigationBuilder IConventionNavigationBuilder.UsePropertyAccessMode(
///
[DebuggerStepThrough]
- bool IConventionNavigationBuilder.CanSetField(string fieldName, bool fromDataAnnotation)
+ bool IConventionPropertyBaseBuilder.CanSetField(string fieldName, bool fromDataAnnotation)
=> CanSetField(
fieldName,
fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+ ///
+ [DebuggerStepThrough]
+ IConventionPropertyBaseBuilder IConventionPropertyBaseBuilder.HasField(string fieldName, bool fromDataAnnotation)
+ => HasField(
+ fieldName,
+ fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+
///
[DebuggerStepThrough]
IConventionNavigationBuilder IConventionNavigationBuilder.HasField(string fieldName, bool fromDataAnnotation)
@@ -122,11 +142,18 @@ IConventionNavigationBuilder IConventionNavigationBuilder.HasField(string fieldN
///
[DebuggerStepThrough]
- bool IConventionNavigationBuilder.CanSetField(FieldInfo fieldInfo, bool fromDataAnnotation)
+ bool IConventionPropertyBaseBuilder.CanSetField(FieldInfo fieldInfo, bool fromDataAnnotation)
=> CanSetField(
fieldInfo,
fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+ ///
+ [DebuggerStepThrough]
+ IConventionPropertyBaseBuilder IConventionPropertyBaseBuilder.HasField(FieldInfo fieldInfo, bool fromDataAnnotation)
+ => HasField(
+ fieldInfo,
+ fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+
///
[DebuggerStepThrough]
IConventionNavigationBuilder IConventionNavigationBuilder.HasField(FieldInfo fieldInfo, bool fromDataAnnotation)
diff --git a/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs b/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs
index 9bfa6617c93..65e35c85ac0 100644
--- a/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalPropertyBuilder.cs
@@ -616,6 +616,18 @@ public virtual InternalPropertyBuilder Attach([NotNull] InternalEntityTypeBuilde
return newPropertyBuilder;
}
+ ///
+ /// 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.
+ ///
+ IConventionPropertyBase IConventionPropertyBaseBuilder.Metadata
+ {
+ [DebuggerStepThrough]
+ get => Metadata;
+ }
+
///
/// 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
@@ -685,6 +697,15 @@ bool IConventionPropertyBuilder.CanSetIsConcurrencyToken(bool? concurrencyToken,
=> CanSetIsConcurrencyToken(
concurrencyToken, 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.
+ ///
+ IConventionPropertyBaseBuilder IConventionPropertyBaseBuilder.HasField(string fieldName, bool fromDataAnnotation)
+ => HasField(fieldName, 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
@@ -694,6 +715,15 @@ bool IConventionPropertyBuilder.CanSetIsConcurrencyToken(bool? concurrencyToken,
IConventionPropertyBuilder IConventionPropertyBuilder.HasField(string fieldName, bool fromDataAnnotation)
=> HasField(fieldName, 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.
+ ///
+ IConventionPropertyBaseBuilder IConventionPropertyBaseBuilder.HasField(FieldInfo fieldInfo, bool fromDataAnnotation)
+ => HasField(fieldInfo, 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
@@ -709,7 +739,7 @@ IConventionPropertyBuilder IConventionPropertyBuilder.HasField(FieldInfo fieldIn
/// 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.CanSetField(string fieldName, bool fromDataAnnotation)
+ bool IConventionPropertyBaseBuilder.CanSetField(string fieldName, bool fromDataAnnotation)
=> CanSetField(fieldName, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
///
@@ -718,9 +748,20 @@ bool IConventionPropertyBuilder.CanSetField(string fieldName, bool fromDataAnnot
/// 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.CanSetField(FieldInfo fieldInfo, bool fromDataAnnotation)
+ bool IConventionPropertyBaseBuilder.CanSetField(FieldInfo fieldInfo, bool fromDataAnnotation)
=> CanSetField(fieldInfo, 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.
+ ///
+ IConventionPropertyBaseBuilder IConventionPropertyBaseBuilder.UsePropertyAccessMode(
+ PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation)
+ => UsePropertyAccessMode(
+ propertyAccessMode, 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
@@ -738,7 +779,7 @@ IConventionPropertyBuilder IConventionPropertyBuilder.UsePropertyAccessMode(
/// 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.CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation)
+ bool IConventionPropertyBaseBuilder.CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation)
=> CanSetPropertyAccessMode(
propertyAccessMode, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
diff --git a/src/EFCore/Metadata/Internal/InternalServicePropertyBuilder.cs b/src/EFCore/Metadata/Internal/InternalServicePropertyBuilder.cs
index a12889a4c1a..461ad8a6f88 100644
--- a/src/EFCore/Metadata/Internal/InternalServicePropertyBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalServicePropertyBuilder.cs
@@ -14,7 +14,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Internal
/// 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 class InternalServicePropertyBuilder : AnnotatableBuilder, IConventionServicePropertyBuilder
+ public class InternalServicePropertyBuilder : InternalPropertyBaseBuilder, IConventionServicePropertyBuilder
{
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -33,41 +33,8 @@ public InternalServicePropertyBuilder([NotNull] ServiceProperty property, [NotNu
/// 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 InternalServicePropertyBuilder HasField([CanBeNull] string fieldName, ConfigurationSource configurationSource)
- {
- if (Metadata.FieldInfo?.GetSimpleMemberName() == fieldName
- || configurationSource.Overrides(Metadata.GetFieldInfoConfigurationSource()))
- {
- Metadata.SetField(fieldName, 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 CanSetField([CanBeNull] string fieldName, ConfigurationSource? configurationSource)
- {
- if (fieldName != null
- && configurationSource.Overrides(Metadata.GetFieldInfoConfigurationSource()))
- {
- var fieldInfo = PropertyBase.GetFieldInfo(
- fieldName, Metadata.DeclaringType, Metadata.Name,
- shouldThrow: false);
- return fieldInfo != null
- && PropertyBase.IsCompatible(
- fieldInfo, Metadata.ClrType, Metadata.DeclaringType.ClrType, Metadata.Name,
- shouldThrow: false);
- }
-
- return Metadata.FieldInfo?.GetSimpleMemberName() == fieldName;
- }
+ public new virtual InternalServicePropertyBuilder HasField([CanBeNull] string fieldName, ConfigurationSource configurationSource)
+ => (InternalServicePropertyBuilder)base.HasField(fieldName, configurationSource);
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -75,17 +42,8 @@ public virtual bool CanSetField([CanBeNull] string fieldName, ConfigurationSourc
/// 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 InternalServicePropertyBuilder HasField([CanBeNull] FieldInfo fieldInfo, ConfigurationSource configurationSource)
- {
- if (configurationSource.Overrides(Metadata.GetFieldInfoConfigurationSource())
- || Equals(Metadata.FieldInfo, fieldInfo))
- {
- Metadata.SetFieldInfo(fieldInfo, configurationSource);
- return this;
- }
-
- return null;
- }
+ public new virtual InternalServicePropertyBuilder HasField([CanBeNull] FieldInfo fieldInfo, ConfigurationSource configurationSource)
+ => (InternalServicePropertyBuilder)base.HasField(fieldInfo, configurationSource);
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -93,13 +51,9 @@ public virtual InternalServicePropertyBuilder HasField([CanBeNull] FieldInfo fie
/// 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 CanSetField([CanBeNull] FieldInfo fieldInfo, ConfigurationSource? configurationSource)
- => (configurationSource.Overrides(Metadata.GetFieldInfoConfigurationSource())
- && (fieldInfo == null
- || PropertyBase.IsCompatible(
- fieldInfo, Metadata.ClrType, Metadata.DeclaringType.ClrType, Metadata.Name,
- shouldThrow: false)))
- || Equals(Metadata.FieldInfo, fieldInfo);
+ public new virtual InternalServicePropertyBuilder UsePropertyAccessMode(
+ PropertyAccessMode? propertyAccessMode, ConfigurationSource configurationSource)
+ => (InternalServicePropertyBuilder)base.UsePropertyAccessMode(propertyAccessMode, configurationSource);
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -162,6 +116,14 @@ public virtual InternalServicePropertyBuilder Attach([NotNull] InternalEntityTyp
return newPropertyBuilder;
}
+ ///
+ /// 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.
+ ///
+ IConventionPropertyBase IConventionPropertyBaseBuilder.Metadata => Metadata;
+
///
/// 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
@@ -170,6 +132,24 @@ public virtual InternalServicePropertyBuilder Attach([NotNull] InternalEntityTyp
///
IConventionServiceProperty IConventionServicePropertyBuilder.Metadata => Metadata;
+ ///
+ /// 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.
+ ///
+ IConventionPropertyBaseBuilder IConventionPropertyBaseBuilder.HasField(string fieldName, bool fromDataAnnotation)
+ => HasField(fieldName, 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.
+ ///
+ IConventionPropertyBaseBuilder IConventionPropertyBaseBuilder.HasField(FieldInfo fieldInfo, bool fromDataAnnotation)
+ => HasField(fieldInfo, 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
@@ -194,7 +174,7 @@ IConventionServicePropertyBuilder IConventionServicePropertyBuilder.HasField(Fie
/// 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 IConventionServicePropertyBuilder.CanSetField(string fieldName, bool fromDataAnnotation)
+ bool IConventionPropertyBaseBuilder.CanSetField(string fieldName, bool fromDataAnnotation)
=> CanSetField(fieldName, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
///
@@ -203,9 +183,41 @@ bool IConventionServicePropertyBuilder.CanSetField(string fieldName, bool fromDa
/// 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 IConventionServicePropertyBuilder.CanSetField(FieldInfo fieldInfo, bool fromDataAnnotation)
+ bool IConventionPropertyBaseBuilder.CanSetField(FieldInfo fieldInfo, bool fromDataAnnotation)
=> CanSetField(fieldInfo, 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.
+ ///
+ IConventionPropertyBaseBuilder IConventionPropertyBaseBuilder.UsePropertyAccessMode(
+ PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation)
+ => UsePropertyAccessMode(
+ propertyAccessMode, 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.
+ ///
+ IConventionServicePropertyBuilder IConventionServicePropertyBuilder.UsePropertyAccessMode(
+ PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation)
+ => UsePropertyAccessMode(
+ propertyAccessMode, 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 IConventionPropertyBaseBuilder.CanSetPropertyAccessMode(PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation)
+ => CanSetPropertyAccessMode(
+ propertyAccessMode, 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/InternalSkipNavigationBuilder.cs b/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs
index a73b38799a4..d8ae5bf3ea8 100644
--- a/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs
+++ b/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs
@@ -319,11 +319,31 @@ public virtual InternalSkipNavigationBuilder AutoInclude(bool? autoInclude, Conf
return null;
}
- IConventionSkipNavigation IConventionSkipNavigationBuilder.Metadata
+ IConventionPropertyBase IConventionPropertyBaseBuilder.Metadata
{
[DebuggerStepThrough] get => Metadata;
}
+ IConventionSkipNavigation IConventionSkipNavigationBuilder.Metadata
+ {
+ [DebuggerStepThrough]
+ get => Metadata;
+ }
+
+ ///
+ [DebuggerStepThrough]
+ IConventionPropertyBaseBuilder IConventionPropertyBaseBuilder.HasField(string fieldName, bool fromDataAnnotation)
+ => HasField(
+ fieldName,
+ fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+
+ ///
+ [DebuggerStepThrough]
+ IConventionPropertyBaseBuilder IConventionPropertyBaseBuilder.HasField(FieldInfo fieldInfo, bool fromDataAnnotation)
+ => HasField(
+ fieldInfo,
+ fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+
///
[DebuggerStepThrough]
IConventionSkipNavigationBuilder IConventionSkipNavigationBuilder.HasField(string fieldName, bool fromDataAnnotation)
@@ -340,18 +360,26 @@ IConventionSkipNavigationBuilder IConventionSkipNavigationBuilder.HasField(Field
///
[DebuggerStepThrough]
- bool IConventionSkipNavigationBuilder.CanSetField(string fieldName, bool fromDataAnnotation)
+ bool IConventionPropertyBaseBuilder.CanSetField(string fieldName, bool fromDataAnnotation)
=> CanSetField(
fieldName,
fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
///
[DebuggerStepThrough]
- bool IConventionSkipNavigationBuilder.CanSetField(FieldInfo fieldInfo, bool fromDataAnnotation)
+ bool IConventionPropertyBaseBuilder.CanSetField(FieldInfo fieldInfo, bool fromDataAnnotation)
=> CanSetField(
fieldInfo,
fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+ ///
+ [DebuggerStepThrough]
+ IConventionPropertyBaseBuilder IConventionPropertyBaseBuilder.UsePropertyAccessMode(
+ PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation)
+ => UsePropertyAccessMode(
+ propertyAccessMode,
+ fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
+
///
[DebuggerStepThrough]
IConventionSkipNavigationBuilder IConventionSkipNavigationBuilder.UsePropertyAccessMode(
@@ -362,7 +390,7 @@ IConventionSkipNavigationBuilder IConventionSkipNavigationBuilder.UsePropertyAcc
///
[DebuggerStepThrough]
- bool IConventionSkipNavigationBuilder.CanSetPropertyAccessMode(
+ bool IConventionPropertyBaseBuilder.CanSetPropertyAccessMode(
PropertyAccessMode? propertyAccessMode, bool fromDataAnnotation)
=> CanSetPropertyAccessMode(
propertyAccessMode,
diff --git a/test/EFCore.Tests/ApiConsistencyTest.cs b/test/EFCore.Tests/ApiConsistencyTest.cs
index c16f4a85f8f..6c2aa597ef6 100644
--- a/test/EFCore.Tests/ApiConsistencyTest.cs
+++ b/test/EFCore.Tests/ApiConsistencyTest.cs
@@ -129,7 +129,19 @@ public override bool TryGetProviderOptionsDelegate(out Action MetadataMethodExceptions { get; } = new HashSet
@@ -142,7 +154,7 @@ public override bool TryGetProviderOptionsDelegate(out Action();
+ modelBuilder.Ignore();
+ modelBuilder.Entity()
+ .HasMany(e => e.Dependents)
+ .WithMany(e => e.ManyToManyPrincipals);
+
+ var model = modelBuilder.FinalizeModel();
+
+ Assert.Equal("_randomField", model.FindEntityType(typeof(ManyToManyNavPrincipal)).FindSkipNavigation("Dependents").GetFieldName());
+ }
+
[ConditionalFact]
public virtual void Navigation_properties_can_set_access_mode_using_navigation_names()
{
@@ -353,8 +369,8 @@ public virtual void Navigation_properties_can_set_access_mode_using_navigation_n
var model = modelBuilder.FinalizeModel();
- var principal = (IEntityType)model.FindEntityType(typeof(ManyToManyNavPrincipal));
- var dependent = (IEntityType)model.FindEntityType(typeof(NavDependent));
+ var principal = model.FindEntityType(typeof(ManyToManyNavPrincipal));
+ var dependent = model.FindEntityType(typeof(NavDependent));
Assert.Equal(PropertyAccessMode.Field, principal.FindSkipNavigation("Dependents").GetPropertyAccessMode());
Assert.Equal(PropertyAccessMode.Property, dependent.FindSkipNavigation("ManyToManyPrincipals").GetPropertyAccessMode());
diff --git a/test/EFCore.Tests/ModelBuilding/TestModel.cs b/test/EFCore.Tests/ModelBuilding/TestModel.cs
index c775958543c..fd5825f4861 100644
--- a/test/EFCore.Tests/ModelBuilding/TestModel.cs
+++ b/test/EFCore.Tests/ModelBuilding/TestModel.cs
@@ -881,9 +881,17 @@ private class OneToOneNavPrincipal
private class ManyToManyNavPrincipal
{
+ private readonly List _randomField;
+
+ public ManyToManyNavPrincipal()
+ {
+ _randomField = new List();
+ }
+
public int Id { get; set; }
public string Name { get; set; }
+ [BackingField("_randomField")]
public List Dependents { get; set; }
}