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 runtime annotation support to model. #23929

Merged
1 commit merged into from
Jan 26, 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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 6 additions & 23 deletions src/EFCore.Design/Migrations/Internal/SnapshotModelProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

namespace Microsoft.EntityFrameworkCore.Migrations.Internal
Expand All @@ -26,7 +24,7 @@ public class SnapshotModelProcessor : ISnapshotModelProcessor
{
private readonly IOperationReporter _operationReporter;
private readonly HashSet<string> _relationalNames;
private readonly IConventionSetBuilder _conventionSetBuilder;
private readonly IModelRuntimeInitializer _modelRuntimeInitializer;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand All @@ -36,15 +34,15 @@ public class SnapshotModelProcessor : ISnapshotModelProcessor
/// </summary>
public SnapshotModelProcessor(
[NotNull] IOperationReporter operationReporter,
[NotNull] IConventionSetBuilder conventionSetBuilder)
[NotNull] IModelRuntimeInitializer modelRuntimeInitializer)
{
_operationReporter = operationReporter;
_relationalNames = new HashSet<string>(
typeof(RelationalAnnotationNames)
.GetRuntimeFields()
.Where(p => p.Name != nameof(RelationalAnnotationNames.Prefix))
.Select(p => ((string)p.GetValue(null)).Substring(RelationalAnnotationNames.Prefix.Length - 1)));
_conventionSetBuilder = conventionSetBuilder;
_modelRuntimeInitializer = modelRuntimeInitializer;
}

/// <summary>
Expand Down Expand Up @@ -82,27 +80,12 @@ public virtual IModel Process(IModel model)
}
}

if (model is IConventionModel conventionModel)
if (model is IMutableModel mutableModel)
{
var conventionSet = _conventionSetBuilder.CreateConventionSet();

var typeMappingConvention = conventionSet.ModelFinalizingConventions.OfType<TypeMappingConvention>().FirstOrDefault();
if (typeMappingConvention != null)
{
typeMappingConvention.ProcessModelFinalizing(conventionModel.Builder, null);
}

var relationalModelConvention =
conventionSet.ModelFinalizedConventions.OfType<RelationalModelConvention>().FirstOrDefault();
if (relationalModelConvention != null)
{
model = relationalModelConvention.ProcessModelFinalized(conventionModel);
}
model = mutableModel.FinalizeModel();
}

return model is IMutableModel mutableModel
? mutableModel.FinalizeModel()
: model;
return _modelRuntimeInitializer.Initialize(model, validationLogger: null);
}

private void ProcessCollection(IEnumerable<IAnnotatable> metadata, string version)
Expand Down
14 changes: 0 additions & 14 deletions src/EFCore.Relational/Design/AnnotationCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,9 @@ public class AnnotationCodeGenerator : IAnnotationCodeGenerator
{
private static readonly ISet<string> _ignoredRelationalAnnotations = new HashSet<string>
{
RelationalAnnotationNames.RelationalModel,
AndriySvyryd marked this conversation as resolved.
Show resolved Hide resolved
RelationalAnnotationNames.CheckConstraints,
RelationalAnnotationNames.Sequences,
RelationalAnnotationNames.DbFunctions,
RelationalAnnotationNames.DefaultMappings,
RelationalAnnotationNames.DefaultColumnMappings,
RelationalAnnotationNames.TableMappings,
RelationalAnnotationNames.TableColumnMappings,
RelationalAnnotationNames.ViewMappings,
RelationalAnnotationNames.ViewColumnMappings,
RelationalAnnotationNames.FunctionMappings,
RelationalAnnotationNames.FunctionColumnMappings,
RelationalAnnotationNames.SqlQueryMappings,
RelationalAnnotationNames.SqlQueryColumnMappings,
RelationalAnnotationNames.ForeignKeyMappings,
RelationalAnnotationNames.TableIndexMappings,
RelationalAnnotationNames.UniqueConstraintMappings,
RelationalAnnotationNames.RelationalOverrides
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public static void SetSchema([NotNull] this IMutableEntityType entityType, [CanB
/// <param name="entityType"> The entity type to get the table mappings for. </param>
/// <returns> The tables to which the entity type is mapped. </returns>
public static IEnumerable<ITableMappingBase> GetDefaultMappings([NotNull] this IEntityType entityType)
=> (IEnumerable<ITableMappingBase>?)entityType[RelationalAnnotationNames.DefaultMappings]
=> (IEnumerable<ITableMappingBase>?)entityType.FindRuntimeAnnotationValue(RelationalAnnotationNames.DefaultMappings)
?? Array.Empty<ITableMappingBase>();

/// <summary>
Expand All @@ -256,7 +256,7 @@ public static IEnumerable<ITableMappingBase> GetDefaultMappings([NotNull] this I
/// <param name="entityType"> The entity type to get the table mappings for. </param>
/// <returns> The tables to which the entity type is mapped. </returns>
public static IEnumerable<ITableMapping> GetTableMappings([NotNull] this IEntityType entityType)
=> (IEnumerable<ITableMapping>?)entityType[RelationalAnnotationNames.TableMappings]
=> (IEnumerable<ITableMapping>?)entityType.FindRuntimeAnnotationValue(RelationalAnnotationNames.TableMappings)
?? Array.Empty<ITableMapping>();

/// <summary>
Expand Down Expand Up @@ -419,7 +419,7 @@ public static void SetViewSchema([NotNull] this IMutableEntityType entityType, [
/// <param name="entityType"> The entity type to get the view mappings for. </param>
/// <returns> The views to which the entity type is mapped. </returns>
public static IEnumerable<IViewMapping> GetViewMappings([NotNull] this IEntityType entityType)
=> (IEnumerable<IViewMapping>?)entityType[RelationalAnnotationNames.ViewMappings]
=> (IEnumerable<IViewMapping>?)entityType.FindRuntimeAnnotationValue(RelationalAnnotationNames.ViewMappings)
?? Array.Empty<IViewMapping>();

/// <summary>
Expand Down Expand Up @@ -493,7 +493,7 @@ public static void SetSqlQuery([NotNull] this IMutableEntityType entityType, [Ca
/// <param name="entityType"> The entity type to get the function mappings for. </param>
/// <returns> The functions to which the entity type is mapped. </returns>
public static IEnumerable<ISqlQueryMapping> GetSqlQueryMappings([NotNull] this IEntityType entityType)
=> (IEnumerable<ISqlQueryMapping>?)entityType[RelationalAnnotationNames.SqlQueryMappings]
=> (IEnumerable<ISqlQueryMapping>?)entityType.FindRuntimeAnnotationValue(RelationalAnnotationNames.SqlQueryMappings)
?? Array.Empty<ISqlQueryMapping>();

/// <summary>
Expand Down Expand Up @@ -558,7 +558,7 @@ public static void SetFunctionName([NotNull] this IMutableEntityType entityType,
/// <param name="entityType"> The entity type to get the function mappings for. </param>
/// <returns> The functions to which the entity type is mapped. </returns>
public static IEnumerable<IFunctionMapping> GetFunctionMappings([NotNull] this IEntityType entityType)
=> (IEnumerable<IFunctionMapping>?)entityType[RelationalAnnotationNames.FunctionMappings]
=> (IEnumerable<IFunctionMapping>?)entityType.FindRuntimeAnnotationValue(RelationalAnnotationNames.FunctionMappings)
?? Array.Empty<IFunctionMapping>();

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public static void SetConstraintName([NotNull] this IMutableForeignKey foreignKe
/// <param name="foreignKey"> The foreign key. </param>
/// <returns> The foreign key constraints to which the foreign key is mapped. </returns>
public static IEnumerable<IForeignKeyConstraint> GetMappedConstraints([NotNull] this IForeignKey foreignKey)
=> (IEnumerable<IForeignKeyConstraint>?)foreignKey[RelationalAnnotationNames.ForeignKeyMappings]
=> (IEnumerable<IForeignKeyConstraint>?)foreignKey.FindRuntimeAnnotationValue(RelationalAnnotationNames.ForeignKeyMappings)
?? Enumerable.Empty<IForeignKeyConstraint>();

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ public static void SetFilter([NotNull] this IMutableIndex index, [CanBeNull] str
/// <param name="index"> The index. </param>
/// <returns> The table indexes to which the index is mapped. </returns>
public static IEnumerable<ITableIndex> GetMappedTableIndexes([NotNull] this IIndex index)
=> (IEnumerable<ITableIndex>?)index[RelationalAnnotationNames.TableIndexMappings]
=> (IEnumerable<ITableIndex>?)index.FindRuntimeAnnotationValue(RelationalAnnotationNames.TableIndexMappings)
?? Enumerable.Empty<ITableIndex>();

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public static void SetName([NotNull] this IMutableKey key, [CanBeNull] string? n
/// <param name="key"> The key. </param>
/// <returns> The unique constraints to which the key is mapped. </returns>
public static IEnumerable<IUniqueConstraint> GetMappedConstraints([NotNull] this IKey key)
=> (IEnumerable<IUniqueConstraint>?)key[RelationalAnnotationNames.UniqueConstraintMappings]
=> (IEnumerable<IUniqueConstraint>?)key.FindRuntimeAnnotationValue(RelationalAnnotationNames.UniqueConstraintMappings)
?? Enumerable.Empty<IUniqueConstraint>();

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,10 @@ public static void SetDefaultSchema([NotNull] this IMutableModel model, [CanBeNu
/// <returns> The database model. </returns>
public static IRelationalModel GetRelationalModel([NotNull] this IModel model)
{
var databaseModel = (IRelationalModel?)model[RelationalAnnotationNames.RelationalModel];
var databaseModel = (IRelationalModel?)model.FindRuntimeAnnotationValue(RelationalAnnotationNames.RelationalModel);
if (databaseModel == null)
{
throw new InvalidOperationException(RelationalStrings.DatabaseModelMissing);
throw new InvalidOperationException(CoreStrings.ModelNotFinalized(nameof(GetRelationalModel)));
}

return databaseModel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ public static void SetColumnType([NotNull] this IMutableProperty property, [CanB
/// <param name="property"> The property. </param>
/// <returns> The default columns to which the property would be mapped. </returns>
public static IEnumerable<IColumnMappingBase> GetDefaultColumnMappings([NotNull] this IProperty property)
=> (IEnumerable<IColumnMappingBase>?)property[RelationalAnnotationNames.DefaultColumnMappings]
=> (IEnumerable<IColumnMappingBase>?)property.FindRuntimeAnnotationValue(RelationalAnnotationNames.DefaultColumnMappings)
?? Enumerable.Empty<IColumnMappingBase>();

/// <summary>
Expand All @@ -371,7 +371,7 @@ public static IEnumerable<IColumnMappingBase> GetDefaultColumnMappings([NotNull]
/// <param name="property"> The property. </param>
/// <returns> The table columns to which the property is mapped. </returns>
public static IEnumerable<IColumnMapping> GetTableColumnMappings([NotNull] this IProperty property)
=> (IEnumerable<IColumnMapping>?)property[RelationalAnnotationNames.TableColumnMappings]
=> (IEnumerable<IColumnMapping>?)property.FindRuntimeAnnotationValue(RelationalAnnotationNames.TableColumnMappings)
?? Enumerable.Empty<IColumnMapping>();

/// <summary>
Expand All @@ -380,7 +380,7 @@ public static IEnumerable<IColumnMapping> GetTableColumnMappings([NotNull] this
/// <param name="property"> The property. </param>
/// <returns> The view columns to which the property is mapped. </returns>
public static IEnumerable<IViewColumnMapping> GetViewColumnMappings([NotNull] this IProperty property)
=> (IEnumerable<IViewColumnMapping>?)property[RelationalAnnotationNames.ViewColumnMappings]
=> (IEnumerable<IViewColumnMapping>?)property.FindRuntimeAnnotationValue(RelationalAnnotationNames.ViewColumnMappings)
?? Enumerable.Empty<IViewColumnMapping>();

/// <summary>
Expand All @@ -389,7 +389,7 @@ public static IEnumerable<IViewColumnMapping> GetViewColumnMappings([NotNull] th
/// <param name="property"> The property. </param>
/// <returns> The SQL query columns to which the property is mapped. </returns>
public static IEnumerable<ISqlQueryColumnMapping> GetSqlQueryColumnMappings([NotNull] this IProperty property)
=> (IEnumerable<ISqlQueryColumnMapping>?)property[RelationalAnnotationNames.SqlQueryColumnMappings]
=> (IEnumerable<ISqlQueryColumnMapping>?)property.FindRuntimeAnnotationValue(RelationalAnnotationNames.SqlQueryColumnMappings)
?? Enumerable.Empty<ISqlQueryColumnMapping>();

/// <summary>
Expand All @@ -398,7 +398,7 @@ public static IEnumerable<ISqlQueryColumnMapping> GetSqlQueryColumnMappings([Not
/// <param name="property"> The property. </param>
/// <returns> The function columns to which the property is mapped. </returns>
public static IEnumerable<IFunctionColumnMapping> GetFunctionColumnMappings([NotNull] this IProperty property)
=> (IEnumerable<IFunctionColumnMapping>?)property[RelationalAnnotationNames.FunctionColumnMappings]
=> (IEnumerable<IFunctionColumnMapping>?)property.FindRuntimeAnnotationValue(RelationalAnnotationNames.FunctionColumnMappings)
?? Enumerable.Empty<IFunctionColumnMapping>();

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ public override EntityFrameworkServicesBuilder TryAddCoreServices()
TryAdd<IMigrationsIdGenerator, MigrationsIdGenerator>();
TryAdd<IKeyValueIndexFactorySource, KeyValueIndexFactorySource>();
TryAdd<IModelCustomizer, RelationalModelCustomizer>();
TryAdd<IModelRuntimeInitializer, RelationalModelRuntimeInitializer>();
TryAdd<IRelationalAnnotationProvider, RelationalAnnotationProvider>();
TryAdd<IMigrationsAnnotationProvider, MigrationsAnnotationProvider>();
TryAdd<IModelValidator, RelationalModelValidator>();
Expand Down Expand Up @@ -198,6 +199,8 @@ public override EntityFrameworkServicesBuilder TryAddCoreServices()
.AddDependencySingleton<RelationalEvaluatableExpressionFilterDependencies>()
.AddDependencySingleton<RelationalQueryTranslationPreprocessorDependencies>()
.AddDependencySingleton<RelationalParameterBasedSqlProcessorDependencies>()
.AddDependencySingleton<RelationalModelDependencies>()
.AddDependencySingleton<RelationalModelRuntimeInitializerDependencies>()
.AddDependencyScoped<MigrationsSqlGeneratorDependencies>()
.AddDependencyScoped<RelationalConventionSetBuilderDependencies>()
.AddDependencyScoped<ModificationCommandBatchFactoryDependencies>()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// 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 Microsoft.Extensions.DependencyInjection;

#nullable enable

namespace Microsoft.EntityFrameworkCore.Infrastructure
{
/// <summary>
/// <para>
/// The relational model service dependencies.
/// </para>
/// <para>
/// This type is typically used by database providers (and other extensions). It is generally
/// not used in application code.
/// </para>
/// <para>
/// Do not construct instances of this class directly from either provider or application code as the
/// constructor signature may change as new dependencies are added. Instead, use this type in
/// your constructor so that an instance will be created and injected automatically by the
/// dependency injection container. To create an instance with some dependent services replaced,
/// first resolve the object from the dependency injection container, then replace selected
/// services using the 'With...' methods. Do not call the constructor at any point in this process.
/// </para>
/// <para>
/// The service lifetime is <see cref="ServiceLifetime.Singleton" />. This means that each
/// <see cref="DbContext" /> instance will use its own instance of this service.
/// The implementation may depend on other services registered with any lifetime.
/// The implementation does not need to be thread-safe.
/// </para>
/// </summary>
public sealed record RelationalModelDependencies
{
/// <summary>
/// <para>
/// Creates the relational model service dependencies.
/// </para>
/// <para>
/// Do not call this constructor directly from either provider or application code as it may change
/// as new dependencies are added. Instead, use this type in your constructor so that an instance
/// will be created and injected automatically by the dependency injection container. To create
/// an instance with some dependent services replaced, first resolve the object from the dependency
/// injection container, then replace selected services using the 'With...' methods. Do not call
/// the constructor at any point in this process.
/// </para>
/// <para>
/// 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.
/// </para>
/// </summary>
[EntityFrameworkInternal]
public RelationalModelDependencies()
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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.Runtime.CompilerServices;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata;

#nullable enable

namespace Microsoft.EntityFrameworkCore.Infrastructure
{
/// <summary>
/// Relational-specific extension methods for <see cref="IModel" />.
/// </summary>
public static class RelationalModelExtensions
{
/// <summary>
/// Returns the relational service dependencies.
/// </summary>
/// <param name="model"> The model. </param>
/// <param name="methodName"> The name of the calling method. </param>
/// <returns> The relational service dependencies. </returns>
public static RelationalModelDependencies GetRelationalDependencies(
[NotNull] this IModel model, [CallerMemberName][CanBeNull] string methodName = "")
=> (RelationalModelDependencies?)model
.FindRuntimeAnnotation(RelationalAnnotationNames.ModelDependencies)?.Value
?? throw new InvalidOperationException(CoreStrings.ModelNotFinalized(methodName));
}
}
Loading