Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new set of interfaces to hide runtime members during model building #24017

Merged
1 commit merged into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
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)
AndriySvyryd marked this conversation as resolved.
Show resolved Hide resolved
=> (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
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>();
roji marked this conversation as resolved.
Show resolved Hide resolved

/// <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);
}
}
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);
roji marked this conversation as resolved.
Show resolved Hide resolved
}

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