diff --git a/src/EFCore/ChangeTracking/CollectionEntry.cs b/src/EFCore/ChangeTracking/CollectionEntry.cs index fca28718d67..031dae40023 100644 --- a/src/EFCore/ChangeTracking/CollectionEntry.cs +++ b/src/EFCore/ChangeTracking/CollectionEntry.cs @@ -283,7 +283,7 @@ protected virtual InternalEntityEntry GetInternalTargetEntry([NotNull] object en : InternalEntry.StateManager.GetOrCreateEntry(entity, Metadata.TargetEntityType); private ICollectionLoader TargetLoader - => _loader ??= Metadata is ISkipNavigation skipNavigation + => _loader ??= Metadata is IRuntimeSkipNavigation skipNavigation ? skipNavigation.GetManyToManyLoader() : new EntityFinderCollectionLoaderAdapter( InternalEntry.StateManager.CreateEntityFinder(Metadata.TargetEntityType), diff --git a/src/EFCore/Extensions/ConventionNavigationExtensions.cs b/src/EFCore/Extensions/ConventionNavigationExtensions.cs index f8e1d46195e..677582fc688 100644 --- a/src/EFCore/Extensions/ConventionNavigationExtensions.cs +++ b/src/EFCore/Extensions/ConventionNavigationExtensions.cs @@ -13,6 +13,7 @@ namespace Microsoft.EntityFrameworkCore /// /// Extension methods for . /// + [Obsolete("Use IConventionNavigation")] public static class ConventionNavigationExtensions { /// diff --git a/src/EFCore/Extensions/IndexExtensions.cs b/src/EFCore/Extensions/IndexExtensions.cs index 07cb4af6da6..6c20e738123 100644 --- a/src/EFCore/Extensions/IndexExtensions.cs +++ b/src/EFCore/Extensions/IndexExtensions.cs @@ -19,72 +19,5 @@ namespace Microsoft.EntityFrameworkCore /// public static class IndexExtensions { - /// - /// - /// Gets a factory for key values based on the index key values taken from various forms of entity data. - /// - /// - /// This method is typically used by database providers (and other extensions). It is generally - /// not used in application code. - /// - /// - /// The index metadata. - /// The type of the index instance. - /// The factory. - public static IDependentKeyValueFactory GetNullableValueFactory([NotNull] this IReadOnlyIndex index) - => index.AsIndex().GetNullableValueFactory(); - - /// - /// - /// Creates a human-readable representation of the given metadata. - /// - /// - /// Warning: Do not rely on the format of the returned string. - /// It is designed for debugging only and may change arbitrarily between releases. - /// - /// - /// The metadata item. - /// Options for generating the string. - /// The number of indent spaces to use before each new line. - /// A human-readable representation. - public static string ToDebugString( - [NotNull] this IReadOnlyIndex index, - MetadataDebugStringOptions options, - int indent = 0) - { - var builder = new StringBuilder(); - var indentString = new string(' ', indent); - - builder.Append(indentString); - - var singleLine = (options & MetadataDebugStringOptions.SingleLine) != 0; - if (singleLine) - { - builder.Append("Index: "); - } - - builder - .AppendJoin( - ", ", - index.Properties.Select( - p => singleLine - ? p.DeclaringEntityType.DisplayName() + "." + p.Name - : p.Name)); - - builder.Append(" " + index.Name ?? ""); - - if (index.IsUnique) - { - builder.Append(" Unique"); - } - - if (!singleLine - && (options & MetadataDebugStringOptions.IncludeAnnotations) != 0) - { - builder.Append(index.AnnotationsToDebugString(indent + 2)); - } - - return builder.ToString(); - } } } diff --git a/src/EFCore/Extensions/MutableNavigationExtensions.cs b/src/EFCore/Extensions/MutableNavigationExtensions.cs index f1d25fb7806..c707b21b1ca 100644 --- a/src/EFCore/Extensions/MutableNavigationExtensions.cs +++ b/src/EFCore/Extensions/MutableNavigationExtensions.cs @@ -13,6 +13,7 @@ namespace Microsoft.EntityFrameworkCore /// /// Extension methods for . /// + [Obsolete("Use IMutableNavigation")] public static class MutableNavigationExtensions { /// diff --git a/src/EFCore/Extensions/NavigationExtensions.cs b/src/EFCore/Extensions/NavigationExtensions.cs index c3bfe1fd178..188e2751fe1 100644 --- a/src/EFCore/Extensions/NavigationExtensions.cs +++ b/src/EFCore/Extensions/NavigationExtensions.cs @@ -3,11 +3,8 @@ using System; using System.Diagnostics; -using System.Text; using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Utilities; #nullable enable @@ -18,6 +15,7 @@ namespace Microsoft.EntityFrameworkCore /// /// Extension methods for . /// + [Obsolete("Use IReadOnlyNavigation")] public static class NavigationExtensions { /// @@ -30,7 +28,7 @@ public static class NavigationExtensions /// type that points to the principal entity, otherwise . /// [DebuggerStepThrough] - [Obsolete("Use INavigation.IsOnDependent")] + [Obsolete("Use IReadOnlyNavigation.IsOnDependent")] public static bool IsDependentToPrincipal([NotNull] this IReadOnlyNavigation navigation) => Check.NotNull(navigation, nameof(navigation)).IsOnDependent; @@ -42,7 +40,7 @@ public static bool IsDependentToPrincipal([NotNull] this IReadOnlyNavigation nav /// if this is a collection property, false if it is a reference property. /// [DebuggerStepThrough] - [Obsolete("Use INavigation.IsCollection")] + [Obsolete("Use IReadOnlyNavigation.IsCollection")] public static bool IsCollection([NotNull] this IReadOnlyNavigation navigation) => Check.NotNull(navigation, nameof(navigation)).IsCollection; @@ -55,7 +53,7 @@ public static bool IsCollection([NotNull] this IReadOnlyNavigation navigation) /// The inverse navigation, or if none is defined. /// [DebuggerStepThrough] - [Obsolete("Use INavigation.Inverse")] + [Obsolete("Use IReadOnlyNavigation.Inverse")] public static IReadOnlyNavigation? FindInverse([NotNull] this IReadOnlyNavigation navigation) => Check.NotNull(navigation, nameof(navigation)).Inverse; @@ -66,7 +64,7 @@ public static bool IsCollection([NotNull] this IReadOnlyNavigation navigation) /// The navigation property to find the target entity type of. /// The target entity type. [DebuggerStepThrough] - [Obsolete("Use INavigation.TargetEntityType")] + [Obsolete("Use IReadOnlyNavigation.TargetEntityType")] public static IReadOnlyEntityType GetTargetType([NotNull] this IReadOnlyNavigation navigation) => Check.NotNull(navigation, nameof(navigation)).TargetEntityType; @@ -75,93 +73,8 @@ public static IReadOnlyEntityType GetTargetType([NotNull] this IReadOnlyNavigati /// /// The navigation property to find whether it should be eager loaded. /// A value indicating whether this navigation should be eager loaded by default. - [Obsolete("Use INavigation.IsEagerLoaded")] + [Obsolete("Use IReadOnlyNavigation.IsEagerLoaded")] public static bool IsEagerLoaded([NotNull] this IReadOnlyNavigation navigation) => Check.NotNull(navigation, nameof(navigation)).IsEagerLoaded; - - /// - /// - /// Creates a human-readable representation of the given metadata. - /// - /// - /// Warning: Do not rely on the format of the returned string. - /// It is designed for debugging only and may change arbitrarily between releases. - /// - /// - /// The metadata item. - /// Options for generating the string. - /// The number of indent spaces to use before each new line. - /// A human-readable representation. - public static string ToDebugString( - [NotNull] this IReadOnlyNavigation navigation, - MetadataDebugStringOptions options, - int indent = 0) - { - var builder = new StringBuilder(); - var indentString = new string(' ', indent); - - builder.Append(indentString); - - var singleLine = (options & MetadataDebugStringOptions.SingleLine) != 0; - if (singleLine) - { - builder.Append($"Navigation: {navigation.DeclaringEntityType.DisplayName()}."); - } - - builder.Append(navigation.Name); - - var field = navigation.GetFieldName(); - if (field == null) - { - builder.Append(" (no field, "); - } - else if (!field.EndsWith(">k__BackingField", StringComparison.Ordinal)) - { - builder.Append($" ({field}, "); - } - else - { - builder.Append(" ("); - } - - builder.Append(navigation.ClrType?.ShortDisplayName()).Append(")"); - - if (navigation.IsCollection) - { - builder.Append(" Collection"); - } - - builder.Append(navigation.IsOnDependent ? " ToPrincipal " : " ToDependent "); - - builder.Append(navigation.TargetEntityType.DisplayName()); - - if (navigation.Inverse != null) - { - builder.Append(" Inverse: ").Append(navigation.Inverse.Name); - } - - if (navigation.GetPropertyAccessMode() != PropertyAccessMode.PreferField) - { - builder.Append(" PropertyAccessMode.").Append(navigation.GetPropertyAccessMode()); - } - - if ((options & MetadataDebugStringOptions.IncludePropertyIndexes) != 0 - && ((Annotatable)navigation).IsReadOnly) - { - var indexes = ((INavigation)navigation).GetPropertyIndexes(); - builder.Append(" ").Append(indexes.Index); - builder.Append(" ").Append(indexes.OriginalValueIndex); - builder.Append(" ").Append(indexes.RelationshipIndex); - builder.Append(" ").Append(indexes.ShadowIndex); - builder.Append(" ").Append(indexes.StoreGenerationIndex); - } - - if (!singleLine && (options & MetadataDebugStringOptions.IncludeAnnotations) != 0) - { - builder.Append(navigation.AnnotationsToDebugString(indent + 2)); - } - - return builder.ToString(); - } } } diff --git a/src/EFCore/Extensions/ServicePropertyExtensions.cs b/src/EFCore/Extensions/ServicePropertyExtensions.cs deleted file mode 100644 index 179bcd5221d..00000000000 --- a/src/EFCore/Extensions/ServicePropertyExtensions.cs +++ /dev/null @@ -1,69 +0,0 @@ -// 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.Text; -using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; - -#nullable enable - -// ReSharper disable once CheckNamespace -namespace Microsoft.EntityFrameworkCore -{ - /// - /// Extension methods for . - /// - public static class ServicePropertyExtensions - { - /// - /// - /// Creates a human-readable representation of the given metadata. - /// - /// - /// Warning: Do not rely on the format of the returned string. - /// It is designed for debugging only and may change arbitrarily between releases. - /// - /// - /// The metadata item. - /// Options for generating the string. - /// The number of indent spaces to use before each new line. - /// A human-readable representation. - public static string ToDebugString( - [NotNull] this IReadOnlyServiceProperty serviceProperty, - MetadataDebugStringOptions options, - int indent = 0) - { - var builder = new StringBuilder(); - var indentString = new string(' ', indent); - - builder.Append(indentString); - - var singleLine = (options & MetadataDebugStringOptions.SingleLine) != 0; - if (singleLine) - { - builder.Append("Service property: ").Append(serviceProperty.DeclaringType.DisplayName()).Append("."); - } - - builder.Append(serviceProperty.Name); - - if (serviceProperty.GetFieldName() == null) - { - builder.Append(" (no field, "); - } - else - { - builder.Append(" (").Append(serviceProperty.GetFieldName()).Append(", "); - } - - builder.Append(serviceProperty.ClrType?.ShortDisplayName()).Append(")"); - - if (!singleLine && (options & MetadataDebugStringOptions.IncludeAnnotations) != 0) - { - builder.Append(serviceProperty.AnnotationsToDebugString(indent + 2)); - } - - return builder.ToString(); - } - } -} diff --git a/src/EFCore/Extensions/SkipNavigationExtensions.cs b/src/EFCore/Extensions/SkipNavigationExtensions.cs deleted file mode 100644 index 7655b32917b..00000000000 --- a/src/EFCore/Extensions/SkipNavigationExtensions.cs +++ /dev/null @@ -1,104 +0,0 @@ -// 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; -using System.Text; -using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Metadata.Internal; - -#nullable enable - -// ReSharper disable once CheckNamespace -namespace Microsoft.EntityFrameworkCore -{ - /// - /// Extension methods for . - /// - public static class SkipNavigationExtensions - { - /// - /// - /// Creates a human-readable representation of the given metadata. - /// - /// - /// Warning: Do not rely on the format of the returned string. - /// It is designed for debugging only and may change arbitrarily between releases. - /// - /// - /// The metadata item. - /// Options for generating the string. - /// The number of indent spaces to use before each new line. - /// A human-readable representation. - public static string ToDebugString( - [NotNull] this IReadOnlySkipNavigation navigation, - MetadataDebugStringOptions options, - int indent = 0) - { - var builder = new StringBuilder(); - var indentString = new string(' ', indent); - - builder.Append(indentString); - - var singleLine = (options & MetadataDebugStringOptions.SingleLine) != 0; - if (singleLine) - { - builder.Append($"SkipNavigation: {navigation.DeclaringEntityType.DisplayName()}."); - } - - builder.Append(navigation.Name); - - var field = navigation.GetFieldName(); - if (field == null) - { - builder.Append(" (no field, "); - } - else if (!field.EndsWith(">k__BackingField", StringComparison.Ordinal)) - { - builder.Append($" ({field}, "); - } - else - { - builder.Append(" ("); - } - - builder.Append(navigation.ClrType?.ShortDisplayName()).Append(")"); - - if (navigation.IsCollection) - { - builder.Append(" Collection"); - } - - builder.Append(navigation.TargetEntityType.DisplayName()); - - if (navigation.Inverse != null) - { - builder.Append(" Inverse: ").Append(navigation.Inverse.Name); - } - - if (navigation.GetPropertyAccessMode() != PropertyAccessMode.PreferField) - { - builder.Append(" PropertyAccessMode.").Append(navigation.GetPropertyAccessMode()); - } - - if ((options & MetadataDebugStringOptions.IncludePropertyIndexes) != 0 - && ((Annotatable)navigation).IsReadOnly) - { - var indexes = ((ISkipNavigation)navigation).GetPropertyIndexes(); - builder.Append(" ").Append(indexes.Index); - builder.Append(" ").Append(indexes.OriginalValueIndex); - builder.Append(" ").Append(indexes.RelationshipIndex); - builder.Append(" ").Append(indexes.ShadowIndex); - builder.Append(" ").Append(indexes.StoreGenerationIndex); - } - - if (!singleLine && (options & MetadataDebugStringOptions.IncludeAnnotations) != 0) - { - builder.Append(navigation.AnnotationsToDebugString(indent + 2)); - } - - return builder.ToString(); - } - } -} diff --git a/src/EFCore/Metadata/IConventionNavigationBase.cs b/src/EFCore/Metadata/IConventionNavigationBase.cs index bfb0a14270b..98c832b8445 100644 --- a/src/EFCore/Metadata/IConventionNavigationBase.cs +++ b/src/EFCore/Metadata/IConventionNavigationBase.cs @@ -26,7 +26,7 @@ public interface IConventionNavigationBase : IReadOnlyNavigationBase, IConventio /// The configured value. bool? SetIsEagerLoaded(bool? eagerLoaded, bool fromDataAnnotation = false) { - this.SetOrRemoveAnnotation(CoreAnnotationNames.EagerLoaded, eagerLoaded, fromDataAnnotation); + SetOrRemoveAnnotation(CoreAnnotationNames.EagerLoaded, eagerLoaded, fromDataAnnotation); return eagerLoaded; } diff --git a/src/EFCore/Metadata/IIndex.cs b/src/EFCore/Metadata/IIndex.cs index 5bf0739353f..5993a0f8afd 100644 --- a/src/EFCore/Metadata/IIndex.cs +++ b/src/EFCore/Metadata/IIndex.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Infrastructure; #nullable enable @@ -24,5 +25,19 @@ public interface IIndex : IReadOnlyIndex, IAnnotatable /// may be defined on a base type). /// new IEntityType DeclaringEntityType { get; } + + /// + /// + /// Gets a factory for key values based on the index key values taken from various forms of entity data. + /// + /// + /// This method is typically used by database providers (and other extensions). It is generally + /// not used in application code. + /// + /// + /// The type of the index instance. + /// The factory. + IDependentKeyValueFactory GetNullableValueFactory(); + } } diff --git a/src/EFCore/Metadata/IMutableNavigationBase.cs b/src/EFCore/Metadata/IMutableNavigationBase.cs index 43de45380a2..d3676a21bca 100644 --- a/src/EFCore/Metadata/IMutableNavigationBase.cs +++ b/src/EFCore/Metadata/IMutableNavigationBase.cs @@ -23,6 +23,6 @@ public interface IMutableNavigationBase : IReadOnlyNavigationBase, IMutablePrope /// /// A value indicating whether this navigation should be eager loaded by default. void SetIsEagerLoaded(bool? eagerLoaded) - => this.SetOrRemoveAnnotation(CoreAnnotationNames.EagerLoaded, eagerLoaded); + => SetOrRemoveAnnotation(CoreAnnotationNames.EagerLoaded, eagerLoaded); } } diff --git a/src/EFCore/Metadata/INavigationBase.cs b/src/EFCore/Metadata/INavigationBase.cs index 0c986dcb864..5a0c4f50810 100644 --- a/src/EFCore/Metadata/INavigationBase.cs +++ b/src/EFCore/Metadata/INavigationBase.cs @@ -43,6 +43,13 @@ public interface INavigationBase : IReadOnlyNavigationBase, IPropertyBase get => (INavigationBase?)((IReadOnlyNavigationBase)this).Inverse; } + /// + /// Gets the for this navigation property, if it's a collection + /// navigation. + /// + /// The accessor. + IClrCollectionAccessor? GetCollectionAccessor(); + /// /// Calls for a to mark it as loaded /// when a no-tracking query has eagerly loaded this relationship. diff --git a/src/EFCore/Metadata/IReadOnlyIndex.cs b/src/EFCore/Metadata/IReadOnlyIndex.cs index 0c382a2811d..3b65ded1669 100644 --- a/src/EFCore/Metadata/IReadOnlyIndex.cs +++ b/src/EFCore/Metadata/IReadOnlyIndex.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; +using System.Linq; +using System.Text; using Microsoft.EntityFrameworkCore.Infrastructure; #nullable enable @@ -34,5 +36,54 @@ public interface IReadOnlyIndex : IReadOnlyAnnotatable /// may be defined on a base type). /// IReadOnlyEntityType DeclaringEntityType { get; } + + /// + /// + /// Creates a human-readable representation of the given metadata. + /// + /// + /// Warning: Do not rely on the format of the returned string. + /// It is designed for debugging only and may change arbitrarily between releases. + /// + /// + /// Options for generating the string. + /// The number of indent spaces to use before each new line. + /// A human-readable representation. + string ToDebugString(MetadataDebugStringOptions options, int indent = 0) + { + var builder = new StringBuilder(); + var indentString = new string(' ', indent); + + builder.Append(indentString); + + var singleLine = (options & MetadataDebugStringOptions.SingleLine) != 0; + if (singleLine) + { + builder.Append("Index: "); + } + + builder + .AppendJoin( + ", ", + Properties.Select( + p => singleLine + ? p.DeclaringEntityType.DisplayName() + "." + p.Name + : p.Name)); + + builder.Append(" " + Name ?? ""); + + if (IsUnique) + { + builder.Append(" Unique"); + } + + if (!singleLine + && (options & MetadataDebugStringOptions.IncludeAnnotations) != 0) + { + builder.Append(AnnotationsToDebugString(indent + 2)); + } + + return builder.ToString(); + } } } diff --git a/src/EFCore/Metadata/IReadOnlyNavigation.cs b/src/EFCore/Metadata/IReadOnlyNavigation.cs index 762bcce3525..60d274704ad 100644 --- a/src/EFCore/Metadata/IReadOnlyNavigation.cs +++ b/src/EFCore/Metadata/IReadOnlyNavigation.cs @@ -1,7 +1,10 @@ // 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; using System.Diagnostics; +using System.Text; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata.Internal; #nullable enable @@ -63,15 +66,6 @@ bool IsOnDependent get => ForeignKey.DependentToPrincipal == this; } - /// - /// Gets the for this navigation property, if it's a collection - /// navigation. - /// - /// The accessor. - [DebuggerStepThrough] - new IClrCollectionAccessor? GetCollectionAccessor() - => ((Navigation)this).CollectionAccessor; - /// /// Gets the entity type that this navigation property belongs to. /// @@ -109,12 +103,84 @@ bool IReadOnlyNavigationBase.IsCollection } /// - /// Gets the for this navigation property, if it's a collection - /// navigation. + /// + /// Creates a human-readable representation of the given metadata. + /// + /// + /// Warning: Do not rely on the format of the returned string. + /// It is designed for debugging only and may change arbitrarily between releases. + /// /// - /// The accessor. - [DebuggerStepThrough] - IClrCollectionAccessor? IReadOnlyNavigationBase.GetCollectionAccessor() - => GetCollectionAccessor(); + /// Options for generating the string. + /// The number of indent spaces to use before each new line. + /// A human-readable representation. + string ToDebugString(MetadataDebugStringOptions options, int indent = 0) + { + var builder = new StringBuilder(); + var indentString = new string(' ', indent); + + builder.Append(indentString); + + var singleLine = (options & MetadataDebugStringOptions.SingleLine) != 0; + if (singleLine) + { + builder.Append($"Navigation: {DeclaringEntityType.DisplayName()}."); + } + + builder.Append(Name); + + var field = GetFieldName(); + if (field == null) + { + builder.Append(" (no field, "); + } + else if (!field.EndsWith(">k__BackingField", StringComparison.Ordinal)) + { + builder.Append($" ({field}, "); + } + else + { + builder.Append(" ("); + } + + builder.Append(ClrType?.ShortDisplayName()).Append(")"); + + if (IsCollection) + { + builder.Append(" Collection"); + } + + builder.Append(IsOnDependent ? " ToPrincipal " : " ToDependent "); + + builder.Append(TargetEntityType.DisplayName()); + + if (Inverse != null) + { + builder.Append(" Inverse: ").Append(Inverse.Name); + } + + if (GetPropertyAccessMode() != PropertyAccessMode.PreferField) + { + builder.Append(" PropertyAccessMode.").Append(GetPropertyAccessMode()); + } + + if ((options & MetadataDebugStringOptions.IncludePropertyIndexes) != 0 + && ((Annotatable)this).IsReadOnly) + { + var indexes = ((INavigation)this).GetPropertyIndexes(); + builder.Append(" ").Append(indexes.Index); + builder.Append(" ").Append(indexes.OriginalValueIndex); + builder.Append(" ").Append(indexes.RelationshipIndex); + builder.Append(" ").Append(indexes.ShadowIndex); + builder.Append(" ").Append(indexes.StoreGenerationIndex); + } + + if (!singleLine && (options & MetadataDebugStringOptions.IncludeAnnotations) != 0) + { + builder.Append(AnnotationsToDebugString(indent + 2)); + } + + return builder.ToString(); + } } } diff --git a/src/EFCore/Metadata/IReadOnlyNavigationBase.cs b/src/EFCore/Metadata/IReadOnlyNavigationBase.cs index df48ee0f5c1..9795e67b8cb 100644 --- a/src/EFCore/Metadata/IReadOnlyNavigationBase.cs +++ b/src/EFCore/Metadata/IReadOnlyNavigationBase.cs @@ -37,12 +37,5 @@ public interface IReadOnlyNavigationBase : IReadOnlyPropertyBase /// bool IsEagerLoaded => (bool?)this[CoreAnnotationNames.EagerLoaded] ?? false; - - /// - /// Gets the for this navigation property, if it's a collection - /// navigation. - /// - /// The accessor. - IClrCollectionAccessor? GetCollectionAccessor(); } } diff --git a/src/EFCore/Metadata/IReadOnlyServiceProperty.cs b/src/EFCore/Metadata/IReadOnlyServiceProperty.cs index 2fb7e894d14..7ed115d30dd 100644 --- a/src/EFCore/Metadata/IReadOnlyServiceProperty.cs +++ b/src/EFCore/Metadata/IReadOnlyServiceProperty.cs @@ -1,6 +1,9 @@ // 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.Text; +using Microsoft.EntityFrameworkCore.Infrastructure; + #nullable enable namespace Microsoft.EntityFrameworkCore.Metadata @@ -20,5 +23,51 @@ public interface IReadOnlyServiceProperty : IReadOnlyPropertyBase /// The for this property. /// ServiceParameterBinding? ParameterBinding { get; } + + /// + /// + /// Creates a human-readable representation of the given metadata. + /// + /// + /// Warning: Do not rely on the format of the returned string. + /// It is designed for debugging only and may change arbitrarily between releases. + /// + /// + /// Options for generating the string. + /// The number of indent spaces to use before each new line. + /// A human-readable representation. + string ToDebugString(MetadataDebugStringOptions options, int indent = 0) + { + var builder = new StringBuilder(); + var indentString = new string(' ', indent); + + builder.Append(indentString); + + var singleLine = (options & MetadataDebugStringOptions.SingleLine) != 0; + if (singleLine) + { + builder.Append("Service property: ").Append(DeclaringType.DisplayName()).Append("."); + } + + builder.Append(Name); + + if (GetFieldName() == null) + { + builder.Append(" (no field, "); + } + else + { + builder.Append(" (").Append(GetFieldName()).Append(", "); + } + + builder.Append(ClrType?.ShortDisplayName()).Append(")"); + + if (!singleLine && (options & MetadataDebugStringOptions.IncludeAnnotations) != 0) + { + builder.Append(AnnotationsToDebugString(indent + 2)); + } + + return builder.ToString(); + } } } diff --git a/src/EFCore/Metadata/IReadOnlySkipNavigation.cs b/src/EFCore/Metadata/IReadOnlySkipNavigation.cs index c1179d75311..7a960002163 100644 --- a/src/EFCore/Metadata/IReadOnlySkipNavigation.cs +++ b/src/EFCore/Metadata/IReadOnlySkipNavigation.cs @@ -1,7 +1,10 @@ // 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; using System.Diagnostics; +using System.Text; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata.Internal; #nullable enable @@ -45,11 +48,82 @@ IReadOnlyNavigationBase IReadOnlyNavigationBase.Inverse bool IsOnDependent { get; } /// - /// Gets the for this navigation property, if it's a collection - /// navigation. + /// + /// Creates a human-readable representation of the given metadata. + /// + /// + /// Warning: Do not rely on the format of the returned string. + /// It is designed for debugging only and may change arbitrarily between releases. + /// /// - /// The accessor. - IClrCollectionAccessor? IReadOnlyNavigationBase.GetCollectionAccessor() - => ((SkipNavigation)this).CollectionAccessor; + /// Options for generating the string. + /// The number of indent spaces to use before each new line. + /// A human-readable representation. + string ToDebugString(MetadataDebugStringOptions options, int indent = 0) + { + var builder = new StringBuilder(); + var indentString = new string(' ', indent); + + builder.Append(indentString); + + var singleLine = (options & MetadataDebugStringOptions.SingleLine) != 0; + if (singleLine) + { + builder.Append($"SkipNavigation: {DeclaringEntityType.DisplayName()}."); + } + + builder.Append(Name); + + var field = GetFieldName(); + if (field == null) + { + builder.Append(" (no field, "); + } + else if (!field.EndsWith(">k__BackingField", StringComparison.Ordinal)) + { + builder.Append($" ({field}, "); + } + else + { + builder.Append(" ("); + } + + builder.Append(ClrType?.ShortDisplayName()).Append(")"); + + if (IsCollection) + { + builder.Append(" Collection"); + } + + builder.Append(TargetEntityType.DisplayName()); + + if (Inverse != null) + { + builder.Append(" Inverse: ").Append(Inverse.Name); + } + + if (GetPropertyAccessMode() != PropertyAccessMode.PreferField) + { + builder.Append(" PropertyAccessMode.").Append(GetPropertyAccessMode()); + } + + if ((options & MetadataDebugStringOptions.IncludePropertyIndexes) != 0 + && ((Annotatable)this).IsReadOnly) + { + var indexes = ((ISkipNavigation)this).GetPropertyIndexes(); + builder.Append(" ").Append(indexes.Index); + builder.Append(" ").Append(indexes.OriginalValueIndex); + builder.Append(" ").Append(indexes.RelationshipIndex); + builder.Append(" ").Append(indexes.ShadowIndex); + builder.Append(" ").Append(indexes.StoreGenerationIndex); + } + + if (!singleLine && (options & MetadataDebugStringOptions.IncludeAnnotations) != 0) + { + builder.Append(AnnotationsToDebugString(indent + 2)); + } + + return builder.ToString(); + } } } diff --git a/src/EFCore/Metadata/Internal/IndexExtensions.cs b/src/EFCore/Metadata/Internal/IRuntimeSkipNavigation.cs similarity index 78% rename from src/EFCore/Metadata/Internal/IndexExtensions.cs rename to src/EFCore/Metadata/Internal/IRuntimeSkipNavigation.cs index f99b66dc1e3..a42369eaa87 100644 --- a/src/EFCore/Metadata/Internal/IndexExtensions.cs +++ b/src/EFCore/Metadata/Internal/IRuntimeSkipNavigation.cs @@ -1,11 +1,10 @@ // 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.Runtime.CompilerServices; -using JetBrains.Annotations; - #nullable enable +using Microsoft.EntityFrameworkCore.Internal; + namespace Microsoft.EntityFrameworkCore.Metadata.Internal { /// @@ -14,7 +13,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 static class IndexExtensions + public interface IRuntimeSkipNavigation : ISkipNavigation { /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -22,7 +21,6 @@ public static class IndexExtensions /// 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 static Index AsIndex([NotNull] this IReadOnlyIndex index, [NotNull] [CallerMemberName] string methodName = "") - => MetadataExtensions.AsConcreteMetadataType(index, methodName); + ICollectionLoader GetManyToManyLoader(); } } diff --git a/src/EFCore/Metadata/Internal/Index.cs b/src/EFCore/Metadata/Internal/Index.cs index 78fb778c0a9..ed2fd159121 100644 --- a/src/EFCore/Metadata/Internal/Index.cs +++ b/src/EFCore/Metadata/Internal/Index.cs @@ -242,7 +242,7 @@ public virtual IDependentKeyValueFactory GetNullableValueFactory() /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public override string ToString() - => this.ToDebugString(MetadataDebugStringOptions.SingleLineDefault); + => ((IIndex)this).ToDebugString(MetadataDebugStringOptions.SingleLineDefault); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -252,8 +252,8 @@ public override string ToString() /// public virtual DebugView DebugView => new( - () => this.ToDebugString(MetadataDebugStringOptions.ShortDefault), - () => this.ToDebugString(MetadataDebugStringOptions.LongDefault)); + () => ((IIndex)this).ToDebugString(MetadataDebugStringOptions.ShortDefault), + () => ((IIndex)this).ToDebugString(MetadataDebugStringOptions.LongDefault)); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/Metadata/Internal/InternalNavigationBuilder.cs b/src/EFCore/Metadata/Internal/InternalNavigationBuilder.cs index 02a4477eba9..ce6b071f587 100644 --- a/src/EFCore/Metadata/Internal/InternalNavigationBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalNavigationBuilder.cs @@ -84,7 +84,15 @@ public virtual bool CanSetAutoInclude(bool? autoInclude, ConfigurationSource con { if (CanSetAutoInclude(autoInclude, configurationSource)) { - Metadata.SetIsEagerLoaded(autoInclude, configurationSource); + if (configurationSource == ConfigurationSource.Explicit) + { + ((IMutableNavigation)Metadata).SetIsEagerLoaded(autoInclude); + } + else + { + ((IConventionNavigation)Metadata).SetIsEagerLoaded( + autoInclude, configurationSource == ConfigurationSource.DataAnnotation); + } return this; } diff --git a/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs b/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs index 096999b35db..49215affa7e 100644 --- a/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalSkipNavigationBuilder.cs @@ -335,7 +335,15 @@ public virtual bool CanSetAutoInclude(bool? autoInclude, ConfigurationSource con { if (CanSetAutoInclude(autoInclude, configurationSource)) { - Metadata.SetIsEagerLoaded(autoInclude, configurationSource); + if (configurationSource == ConfigurationSource.Explicit) + { + ((IMutableSkipNavigation)Metadata).SetIsEagerLoaded(autoInclude); + } + else + { + ((IConventionSkipNavigation)Metadata).SetIsEagerLoaded( + autoInclude, configurationSource == ConfigurationSource.DataAnnotation); + } return this; } diff --git a/src/EFCore/Metadata/Internal/Navigation.cs b/src/EFCore/Metadata/Internal/Navigation.cs index fd7f02bc040..871050a2218 100644 --- a/src/EFCore/Metadata/Internal/Navigation.cs +++ b/src/EFCore/Metadata/Internal/Navigation.cs @@ -172,15 +172,6 @@ public override void UpdateConfigurationSource(ConfigurationSource configuration } } - /// - /// 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? SetIsEagerLoaded(bool? eagerLoaded, ConfigurationSource configurationSource) - => (bool?)SetOrRemoveAnnotation(CoreAnnotationNames.EagerLoaded, eagerLoaded, configurationSource)?.Value; - /// /// 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 @@ -337,7 +328,7 @@ public virtual IClrCollectionAccessor? CollectionAccessor /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public override string ToString() - => this.ToDebugString(MetadataDebugStringOptions.SingleLineDefault); + => ((IReadOnlyNavigation)this).ToDebugString(MetadataDebugStringOptions.SingleLineDefault); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -347,8 +338,8 @@ public override string ToString() /// public virtual DebugView DebugView => new( - () => this.ToDebugString(MetadataDebugStringOptions.ShortDefault), - () => this.ToDebugString(MetadataDebugStringOptions.LongDefault)); + () => ((IReadOnlyNavigation)this).ToDebugString(MetadataDebugStringOptions.ShortDefault), + () => ((IReadOnlyNavigation)this).ToDebugString(MetadataDebugStringOptions.LongDefault)); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -392,5 +383,14 @@ IConventionAnnotatableBuilder IConventionAnnotatable.Builder { [DebuggerStepThrough] get => Builder; } + + /// + /// 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. + /// + IClrCollectionAccessor? INavigationBase.GetCollectionAccessor() + => CollectionAccessor; } } diff --git a/src/EFCore/Metadata/Internal/NavigationExtensions.cs b/src/EFCore/Metadata/Internal/NavigationExtensions.cs index 99681905a3e..37cb9c34a1b 100644 --- a/src/EFCore/Metadata/Internal/NavigationExtensions.cs +++ b/src/EFCore/Metadata/Internal/NavigationExtensions.cs @@ -1,9 +1,7 @@ // 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.Runtime.CompilerServices; using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore.Internal; #nullable enable @@ -27,23 +25,5 @@ public static MemberIdentity CreateMemberIdentity([CanBeNull] this IReadOnlyNavi => navigation?.GetIdentifyingMemberInfo() == null ? MemberIdentity.Create(navigation?.Name) : MemberIdentity.Create(navigation.GetIdentifyingMemberInfo()); - - /// - /// 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 static Navigation AsNavigation([NotNull] this IReadOnlyNavigation navigation, [NotNull] [CallerMemberName] string methodName = "") - => MetadataExtensions.AsConcreteMetadataType(navigation, methodName); - - /// - /// 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 static ICollectionLoader GetManyToManyLoader([NotNull] this IReadOnlySkipNavigation navigation) - => ((SkipNavigation)navigation).ManyToManyLoader; } } diff --git a/src/EFCore/Metadata/Internal/PropertyBaseExtensions.cs b/src/EFCore/Metadata/Internal/PropertyBaseExtensions.cs index 7214f59fafc..7d44530529e 100644 --- a/src/EFCore/Metadata/Internal/PropertyBaseExtensions.cs +++ b/src/EFCore/Metadata/Internal/PropertyBaseExtensions.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; diff --git a/src/EFCore/Metadata/Internal/ServiceProperty.cs b/src/EFCore/Metadata/Internal/ServiceProperty.cs index 8dba52349f7..cdc4b9da11f 100644 --- a/src/EFCore/Metadata/Internal/ServiceProperty.cs +++ b/src/EFCore/Metadata/Internal/ServiceProperty.cs @@ -241,7 +241,7 @@ IEntityType IServiceProperty.DeclaringEntityType /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public override string ToString() - => this.ToDebugString(MetadataDebugStringOptions.SingleLineDefault); + => ((IServiceProperty)this).ToDebugString(MetadataDebugStringOptions.SingleLineDefault); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -251,7 +251,7 @@ public override string ToString() /// public virtual DebugView DebugView => new( - () => this.ToDebugString(MetadataDebugStringOptions.ShortDefault), - () => this.ToDebugString(MetadataDebugStringOptions.LongDefault)); + () => ((IServiceProperty)this).ToDebugString(MetadataDebugStringOptions.ShortDefault), + () => ((IServiceProperty)this).ToDebugString(MetadataDebugStringOptions.LongDefault)); } } diff --git a/src/EFCore/Metadata/Internal/ServicePropertyExtensions.cs b/src/EFCore/Metadata/Internal/ServicePropertyExtensions.cs deleted file mode 100644 index 23beb340456..00000000000 --- a/src/EFCore/Metadata/Internal/ServicePropertyExtensions.cs +++ /dev/null @@ -1,30 +0,0 @@ -// 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.Runtime.CompilerServices; -using JetBrains.Annotations; - -#nullable enable - -namespace Microsoft.EntityFrameworkCore.Metadata.Internal -{ - /// - /// 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 static class ServicePropertyExtensions - { - /// - /// 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 static ServiceProperty AsServiceProperty( - [NotNull] this IReadOnlyServiceProperty serviceProperty, - [NotNull] [CallerMemberName] string methodName = "") - => MetadataExtensions.AsConcreteMetadataType(serviceProperty, methodName); - } -} diff --git a/src/EFCore/Metadata/Internal/SkipNavigation.cs b/src/EFCore/Metadata/Internal/SkipNavigation.cs index dd990e8ddb4..565efa04880 100644 --- a/src/EFCore/Metadata/Internal/SkipNavigation.cs +++ b/src/EFCore/Metadata/Internal/SkipNavigation.cs @@ -22,7 +22,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 SkipNavigation : PropertyBase, IMutableSkipNavigation, IConventionSkipNavigation, ISkipNavigation + public class SkipNavigation : PropertyBase, IMutableSkipNavigation, IConventionSkipNavigation, IRuntimeSkipNavigation { private ConfigurationSource? _foreignKeyConfigurationSource; private ConfigurationSource? _inverseConfigurationSource; @@ -322,15 +322,6 @@ public virtual void UpdateForeignKeyConfigurationSource(ConfigurationSource conf public virtual void UpdateInverseConfigurationSource(ConfigurationSource configurationSource) => _inverseConfigurationSource = _inverseConfigurationSource.Max(configurationSource); - /// - /// 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? SetIsEagerLoaded(bool? eagerLoaded, ConfigurationSource configurationSource) - => (bool?)SetOrRemoveAnnotation(CoreAnnotationNames.EagerLoaded, eagerLoaded, configurationSource)?.Value; - /// /// 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 @@ -392,10 +383,9 @@ public virtual ICollectionLoader ManyToManyLoader /// 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 DebugView DebugView - => new( - () => this.ToDebugString(MetadataDebugStringOptions.ShortDefault), - () => this.ToDebugString(MetadataDebugStringOptions.LongDefault)); + [DebuggerStepThrough] + public override string ToString() + => ((IReadOnlySkipNavigation)this).ToDebugString(MetadataDebugStringOptions.SingleLineDefault); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -403,9 +393,10 @@ public virtual DebugView DebugView /// 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. /// - [DebuggerStepThrough] - public override string ToString() - => this.ToDebugString(MetadataDebugStringOptions.SingleLineDefault); + public virtual DebugView DebugView + => new( + () => ((IReadOnlySkipNavigation)this).ToDebugString(MetadataDebugStringOptions.ShortDefault), + () => ((IReadOnlySkipNavigation)this).ToDebugString(MetadataDebugStringOptions.LongDefault)); /// IConventionSkipNavigationBuilder IConventionSkipNavigation.Builder @@ -474,5 +465,23 @@ IReadOnlySkipNavigation IReadOnlySkipNavigation.Inverse bool fromDataAnnotation) => SetInverse( (SkipNavigation?)inverse, 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. + /// + IClrCollectionAccessor? INavigationBase.GetCollectionAccessor() + => CollectionAccessor; + + /// + /// 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. + /// + ICollectionLoader IRuntimeSkipNavigation.GetManyToManyLoader() + => ManyToManyLoader; } } diff --git a/test/EFCore.Tests/ApiConsistencyTest.cs b/test/EFCore.Tests/ApiConsistencyTest.cs index 16224df37c2..e5df2764c10 100644 --- a/test/EFCore.Tests/ApiConsistencyTest.cs +++ b/test/EFCore.Tests/ApiConsistencyTest.cs @@ -100,14 +100,6 @@ public override typeof(ConventionForeignKeyExtensions), null, null - ), - ( - typeof(IReadOnlyNavigation), - typeof(NavigationExtensions), - typeof(MutableNavigationExtensions), - typeof(ConventionNavigationExtensions), - null, - null ) }; diff --git a/test/EFCore.Tests/Metadata/Internal/ClrCollectionAccessorFactoryTest.cs b/test/EFCore.Tests/Metadata/Internal/ClrCollectionAccessorFactoryTest.cs index a27667a56b7..2f3723520c2 100644 --- a/test/EFCore.Tests/Metadata/Internal/ClrCollectionAccessorFactoryTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/ClrCollectionAccessorFactoryTest.cs @@ -72,6 +72,9 @@ public object GetOrCreate(object entity, bool forMaterialization) public IComparer GetCurrentValueComparer() => throw new NotImplementedException(); + public IClrCollectionAccessor GetCollectionAccessor() + => throw new NotImplementedException(); + public Type CollectionType { get; } } diff --git a/test/EFCore.Tests/Metadata/Internal/NavigationTest.cs b/test/EFCore.Tests/Metadata/Internal/NavigationTest.cs index d466e20f10b..964ae43682a 100644 --- a/test/EFCore.Tests/Metadata/Internal/NavigationTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/NavigationTest.cs @@ -5,35 +5,12 @@ using System.Collections.Generic; using System.Reflection; using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.EntityFrameworkCore.Infrastructure; using Xunit; namespace Microsoft.EntityFrameworkCore.Metadata.Internal { public class NavigationTest { - [ConditionalFact] - public void Use_of_custom_INavigation_throws() - { - var navigation = new FakeNavigation(); - - Assert.Equal( - CoreStrings.CustomMetadata(nameof(Use_of_custom_INavigation_throws), nameof(IReadOnlyNavigation), nameof(FakeNavigation)), - Assert.Throws(() => navigation.AsNavigation()).Message); - } - - private class FakeNavigation : Annotatable, IReadOnlyNavigation - { - public string Name { get; } - public IReadOnlyTypeBase DeclaringType { get; } - public Type ClrType { get; } - public PropertyInfo PropertyInfo { get; } - public FieldInfo FieldInfo { get; } - public IReadOnlyEntityType DeclaringEntityType { get; } - public IReadOnlyForeignKey ForeignKey { get; } - public bool IsEagerLoaded { get; } - } - [ConditionalFact] public void Can_create_navigation() {