Skip to content

Commit

Permalink
Add a new set of interfaces to hide runtime members during model buil…
Browse files Browse the repository at this point in the history
…ding (#24017)

Part of #19213
  • Loading branch information
AndriySvyryd authored Feb 1, 2021
1 parent cc092eb commit 9a8c6c7
Show file tree
Hide file tree
Showing 339 changed files with 5,622 additions and 3,033 deletions.
38 changes: 23 additions & 15 deletions src/EFCore.Cosmos/Extensions/CosmosEntityTypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace Microsoft.EntityFrameworkCore
{
/// <summary>
/// Extension methods for <see cref="IEntityType" /> for Cosmos metadata.
/// Entity type extension methods for Cosmos metadata.
/// </summary>
public static class CosmosEntityTypeExtensions
{
Expand All @@ -21,13 +21,13 @@ public static class CosmosEntityTypeExtensions
/// </summary>
/// <param name="entityType"> The entity type to get the container name for. </param>
/// <returns> The name of the container to which the entity type is mapped. </returns>
public static string? GetContainer([NotNull] this IEntityType entityType)
public static string? GetContainer([NotNull] this IReadOnlyEntityType entityType)
=> entityType.BaseType != null
? entityType.GetRootType().GetContainer()
: (string?)entityType[CosmosAnnotationNames.ContainerName]
?? GetDefaultContainer(entityType);

private static string? GetDefaultContainer(IEntityType entityType)
private static string? GetDefaultContainer(IReadOnlyEntityType entityType)
=> entityType.IsOwned()
? null
: entityType.Model.GetDefaultContainer()
Expand Down Expand Up @@ -72,11 +72,11 @@ public static void SetContainer(
/// </summary>
/// <param name="entityType"> The entity type to get the containing property name for. </param>
/// <returns> The name of the parent property to which the entity type is mapped. </returns>
public static string? GetContainingPropertyName([NotNull] this IEntityType entityType)
public static string? GetContainingPropertyName([NotNull] this IReadOnlyEntityType entityType)
=> entityType[CosmosAnnotationNames.PropertyName] as string
?? GetDefaultContainingPropertyName(entityType);

private static string? GetDefaultContainingPropertyName(IEntityType entityType)
private static string? GetDefaultContainingPropertyName(IReadOnlyEntityType entityType)
=> entityType.FindOwnership()?.PrincipalToDependent!.Name;

/// <summary>
Expand Down Expand Up @@ -118,7 +118,7 @@ public static void SetContainingPropertyName(
/// </summary>
/// <param name="entityType"> The entity type to get the partition key property name for. </param>
/// <returns> The name of the partition key property. </returns>
public static string? GetPartitionKeyPropertyName([NotNull] this IEntityType entityType)
public static string? GetPartitionKeyPropertyName([NotNull] this IReadOnlyEntityType entityType)
=> entityType[CosmosAnnotationNames.PartitionKeyName] as string;

/// <summary>
Expand Down Expand Up @@ -156,15 +156,15 @@ public static void SetPartitionKeyPropertyName(
?.GetConfigurationSource();

/// <summary>
/// Returns the name of the property that is used to store the etag.
/// Returns the name of the property that is used to store the ETag.
/// </summary>
/// <param name="entityType"> The entity type to get the etag property name for. </param>
/// <returns> The name of the etag property. </returns>
public static string? GetETagPropertyName([NotNull] this IEntityType entityType)
public static string? GetETagPropertyName([NotNull] this IReadOnlyEntityType entityType)
=> entityType[CosmosAnnotationNames.ETagName] as string;

/// <summary>
/// Sets the name of the property that is used to store the etag key.
/// Sets the name of the property that is used to store the ETag key.
/// </summary>
/// <param name="entityType"> The entity type to set the etag property name for. </param>
/// <param name="name"> The name to set. </param>
Expand All @@ -174,9 +174,9 @@ public static void SetETagPropertyName([NotNull] this IMutableEntityType entityT
Check.NullButNotEmpty(name, nameof(name)));

/// <summary>
/// Sets the name of the property that is used to store the etag.
/// Sets the name of the property that is used to store the ETag.
/// </summary>
/// <param name="entityType"> The entity type to set the etag property name for. </param>
/// <param name="entityType"> The entity type to set the ETag property name for. </param>
/// <param name="name"> The name to set. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
public static void SetETagPropertyName(
Expand All @@ -198,15 +198,23 @@ public static void SetETagPropertyName(
?.GetConfigurationSource();

/// <summary>
/// Gets the <see cref="IProperty" /> on this entity that is mapped to cosmos etag, if it exists.
/// Gets the property on this entity that is mapped to cosmos ETag, if it exists.
/// </summary>
/// <param name="entityType"> The entity type to get the etag property for. </param>
/// <returns> The <see cref="IProperty" /> mapped to etag, or null if no property is mapped to etag. </returns>
public static IProperty? GetETagProperty([NotNull] this IEntityType entityType)
/// <param name="entityType"> The entity type to get the ETag property for. </param>
/// <returns> The property mapped to ETag, or <see langword="null" /> if no property is mapped to ETag. </returns>
public static IReadOnlyProperty? GetETagProperty([NotNull] this IReadOnlyEntityType entityType)
{
Check.NotNull(entityType, nameof(entityType));
var etagPropertyName = entityType.GetETagPropertyName();
return !string.IsNullOrEmpty(etagPropertyName) ? entityType.FindProperty(etagPropertyName) : null;
}

/// <summary>
/// Gets the property on this entity that is mapped to cosmos ETag, if it exists.
/// </summary>
/// <param name="entityType"> The entity type to get the ETag property for. </param>
/// <returns> The property mapped to etag, or <see langword="null" /> if no property is mapped to ETag. </returns>
public static IProperty? GetETagProperty([NotNull] this IEntityType entityType)
=> (IProperty?)((IReadOnlyEntityType)entityType).GetETagProperty();
}
}
4 changes: 2 additions & 2 deletions src/EFCore.Cosmos/Extensions/CosmosModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace Microsoft.EntityFrameworkCore
{
/// <summary>
/// Extension methods for <see cref="IModel" /> for Cosmos metadata.
/// Model extension methods for Cosmos metadata.
/// </summary>
public static class CosmosModelExtensions
{
Expand All @@ -21,7 +21,7 @@ public static class CosmosModelExtensions
/// </summary>
/// <param name="model"> The model. </param>
/// <returns> The default container name. </returns>
public static string? GetDefaultContainer([NotNull] this IModel model)
public static string? GetDefaultContainer([NotNull] this IReadOnlyModel model)
=> (string?)model[CosmosAnnotationNames.ContainerName];

/// <summary>
Expand Down
6 changes: 3 additions & 3 deletions src/EFCore.Cosmos/Extensions/CosmosPropertyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
namespace Microsoft.EntityFrameworkCore
{
/// <summary>
/// Extension methods for <see cref="IProperty" /> for Cosmos metadata.
/// Property extension methods for Cosmos metadata.
/// </summary>
public static class CosmosPropertyExtensions
{
Expand All @@ -21,11 +21,11 @@ public static class CosmosPropertyExtensions
/// </summary>
/// <param name="property"> The property. </param>
/// <returns> Returns the property name that the property is mapped to when targeting Cosmos. </returns>
public static string GetJsonPropertyName([NotNull] this IProperty property)
public static string GetJsonPropertyName([NotNull] this IReadOnlyProperty property)
=> (string?)property[CosmosAnnotationNames.PropertyName]
?? GetDefaultJsonPropertyName(property);

private static string GetDefaultJsonPropertyName(IProperty property)
private static string GetDefaultJsonPropertyName(IReadOnlyProperty property)
{
var entityType = property.DeclaringEntityType;
var ownership = entityType.FindOwnership();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static class CosmosEntityTypeExtensions
/// 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.
/// </summary>
public static bool IsDocumentRoot([NotNull] this IEntityType entityType)
public static bool IsDocumentRoot([NotNull] this IReadOnlyEntityType entityType)
=> entityType.BaseType?.IsDocumentRoot()
?? (!entityType.IsOwned()
|| entityType[CosmosAnnotationNames.ContainerName] != null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static class CosmosNavigationExtensions
/// 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.
/// </summary>
public static bool IsEmbedded([NotNull] this INavigation navigation)
public static bool IsEmbedded([NotNull] this IReadOnlyNavigation navigation)
=> !navigation.IsOnDependent
&& !navigation.ForeignKey.DeclaringEntityType.IsDocumentRoot();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ public static class CosmosPropertyExtensions
/// 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.
/// </summary>
public static bool IsOrdinalKeyProperty([NotNull] this IProperty property)
public static bool IsOrdinalKeyProperty([NotNull] this IReadOnlyProperty property)
{
Check.DebugAssert(
property.DeclaringEntityType.IsOwned(), $"Expected {property.DeclaringEntityType.DisplayName()} to be owned.");
Check.DebugAssert(property.GetJsonPropertyName().Length == 0, $"Expected {property.Name} to be non-persisted.");

return property.FindContainingPrimaryKey() is IKey key
return property.FindContainingPrimaryKey() is IReadOnlyKey key
&& key.Properties.Count > 1
&& !property.IsForeignKey()
&& property.ClrType == typeof(int)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static class ScaffoldingEntityTypeAnnotations
/// 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.
/// </summary>
public static string GetDbSetName([NotNull] this IEntityType entityType)
public static string GetDbSetName([NotNull] this IReadOnlyEntityType entityType)
=> (string)entityType[ScaffoldingAnnotationNames.DbSetName]
?? entityType.Name;

Expand Down
13 changes: 11 additions & 2 deletions src/EFCore.Design/Metadata/Internal/ScaffoldingModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,16 @@ public static class ScaffoldingModelExtensions
/// 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.
/// </summary>
public static IDictionary<string, string> GetEntityTypeErrors([NotNull] this IModel model)
public static IReadOnlyDictionary<string, string> GetEntityTypeErrors([NotNull] this IReadOnlyModel model)
=> (IReadOnlyDictionary<string, string>)model[ScaffoldingAnnotationNames.EntityTypeErrors] ?? new Dictionary<string, string>();

/// <summary>
/// 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.
/// </summary>
public static IDictionary<string, string> GetOrCreateEntityTypeErrors([NotNull] this IReadOnlyModel model)
{
var errors = (IDictionary<string, string>)model[ScaffoldingAnnotationNames.EntityTypeErrors];
if (errors == null)
Expand Down Expand Up @@ -50,7 +59,7 @@ public static void SetEntityTypeErrors([NotNull] this IMutableModel model, [NotN
/// 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.
/// </summary>
public static string GetDatabaseName([NotNull] this IModel model)
public static string GetDatabaseName([NotNull] this IReadOnlyModel model)
=> (string)model[ScaffoldingAnnotationNames.DatabaseName];

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static class ScaffoldingPropertyExtensions
/// 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.
/// </summary>
public static int GetColumnOrdinal([NotNull] this IProperty property)
public static int GetColumnOrdinal([NotNull] this IReadOnlyProperty property)
=> (int?)property[ScaffoldingAnnotationNames.ColumnOrdinal] ?? -1;

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,11 @@ protected virtual void GenerateEntityType(

GenerateProperties(builderName, entityType.GetDeclaredProperties(), stringBuilder);

GenerateKeys(builderName, entityType.GetDeclaredKeys(), entityType.FindDeclaredPrimaryKey(), stringBuilder);
GenerateKeys(
builderName,
entityType.GetDeclaredKeys(),
entityType.BaseType == null ? entityType.FindPrimaryKey() : null,
stringBuilder);

GenerateIndexes(builderName, entityType.GetDeclaredIndexes(), stringBuilder);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ public interface ISnapshotModelProcessor
/// 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.
/// </summary>
IModel Process([CanBeNull] IModel model);
IModel Process([CanBeNull] IReadOnlyModel model);
}
}
14 changes: 7 additions & 7 deletions src/EFCore.Design/Migrations/Internal/SnapshotModelProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public SnapshotModelProcessor(
/// 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.
/// </summary>
public virtual IModel Process(IModel model)
public virtual IModel Process(IReadOnlyModel model)
{
if (model == null)
{
Expand Down Expand Up @@ -85,20 +85,20 @@ public virtual IModel Process(IModel model)
model = mutableModel.FinalizeModel();
}

return _modelRuntimeInitializer.Initialize(model, validationLogger: null);
return _modelRuntimeInitializer.Initialize((IModel)model, validationLogger: null);
}

private void ProcessCollection(IEnumerable<IAnnotatable> metadata, string version)
private void ProcessCollection(IEnumerable<IReadOnlyAnnotatable> metadata, string version)
{
foreach (var element in metadata)
{
ProcessElement(element, version);
}
}

private void ProcessElement(IEntityType entityType, string version)
private void ProcessElement(IReadOnlyEntityType entityType, string version)
{
ProcessElement((IAnnotatable)entityType, version);
ProcessElement((IReadOnlyAnnotatable)entityType, version);

if ((version.StartsWith("2.0", StringComparison.Ordinal)
|| version.StartsWith("2.1", StringComparison.Ordinal))
Expand All @@ -109,7 +109,7 @@ private void ProcessElement(IEntityType entityType, string version)
}
}

private void ProcessElement(IAnnotatable metadata, string version)
private void ProcessElement(IReadOnlyAnnotatable metadata, string version)
{
if (version.StartsWith("1.", StringComparison.Ordinal)
&& metadata is IMutableAnnotatable mutableMetadata)
Expand Down Expand Up @@ -141,7 +141,7 @@ private void ProcessElement(IAnnotatable metadata, string version)
}
}

private void UpdateSequences(IModel model, string version)
private void UpdateSequences(IReadOnlyModel model, string version)
{
if ((!version.StartsWith("1.", StringComparison.Ordinal)
&& !version.StartsWith("2.", StringComparison.Ordinal)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,13 @@ private void GenerateDbSets(IModel model)

private void GenerateEntityTypeErrors(IModel model)
{
foreach (var entityTypeError in model.GetEntityTypeErrors())
var errors = model.GetEntityTypeErrors();
foreach (var entityTypeError in errors)
{
_sb.AppendLine($"// {entityTypeError.Value} Please see the warning messages.");
}

if (model.GetEntityTypeErrors().Count > 0)
if (errors.Count > 0)
{
_sb.AppendLine();
}
Expand Down Expand Up @@ -454,11 +455,11 @@ private void GenerateKey(IKey key, IEntityType entityType, bool useDataAnnotatio
if (key.Properties.Count == 1
&& annotations.Count == 0)
{
if (key is Key concreteKey
&& key.Properties.SequenceEqual(
if (key is IConventionKey conventionKey
&& conventionKey.Properties.SequenceEqual(
KeyDiscoveryConvention.DiscoverKeyProperties(
concreteKey.DeclaringEntityType,
concreteKey.DeclaringEntityType.GetProperties())))
conventionKey.DeclaringEntityType,
conventionKey.DeclaringEntityType.GetProperties())))
{
return;
}
Expand Down
Loading

0 comments on commit 9a8c6c7

Please sign in to comment.