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

Store all functions in one annotation #20091

Merged
merged 1 commit into from
Feb 28, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ public virtual void Generate(string builderName, IModel model, IndentedStringBui

var annotations = model.GetAnnotations().ToList();

IgnoreAnnotationTypes(annotations, RelationalAnnotationNames.DbFunction);
IgnoreAnnotations(
annotations,
ChangeDetector.SkipDetectChangesAnnotation,
CoreAnnotationNames.ChangeTrackingStrategy,
CoreAnnotationNames.OwnedTypes,
RelationalAnnotationNames.CheckConstraints,
RelationalAnnotationNames.Sequences,
RelationalAnnotationNames.DbFunctions,
RelationalAnnotationNames.Tables,
RelationalAnnotationNames.Views);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ private IEnumerable<string> GetAnnotationNamespaces(IEnumerable<IAnnotatable> it
CoreAnnotationNames.QueryFilter,
RelationalAnnotationNames.CheckConstraints,
RelationalAnnotationNames.Sequences,
RelationalAnnotationNames.DbFunctions,
RelationalAnnotationNames.Tables,
RelationalAnnotationNames.TableMappings,
RelationalAnnotationNames.TableColumnMappings,
Expand All @@ -251,18 +252,12 @@ private IEnumerable<string> GetAnnotationNamespaces(IEnumerable<IAnnotatable> it
RelationalAnnotationNames.ViewColumnMappings
};

var ignoredAnnotationTypes = new List<string>
{
RelationalAnnotationNames.DbFunction
};

return items.SelectMany(
i => i.GetAnnotations().Select(
a => new { Annotatable = i, Annotation = a })
.Where(
a => a.Annotation.Value != null
&& !ignoredAnnotations.Contains(a.Annotation.Name)
&& !ignoredAnnotationTypes.Any(p => a.Annotation.Name.StartsWith(p, StringComparison.Ordinal)))
&& !ignoredAnnotations.Contains(a.Annotation.Name))
.SelectMany(a => GetProviderType(a.Annotatable, a.Annotation.Value.GetType()).GetNamespaces()));
}

Expand Down
116 changes: 91 additions & 25 deletions src/EFCore.Relational/Extensions/RelationalModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ public static IConventionSequence AddSequence(
/// </returns>
public static IMutableSequence RemoveSequence(
[NotNull] this IMutableModel model, [NotNull] string name, [CanBeNull] string schema = null)
=> Sequence.RemoveSequence(model, name, schema);
=> Sequence.RemoveSequence(Check.NotNull(model, nameof(model)), name, schema);

/// <summary>
/// Removes the <see cref="IConventionSequence" /> with the given name.
Expand All @@ -233,28 +233,28 @@ public static IMutableSequence RemoveSequence(
/// </returns>
public static IConventionSequence RemoveSequence(
[NotNull] this IConventionModel model, [NotNull] string name, [CanBeNull] string schema = null)
=> (IConventionSequence)((IMutableModel)model).RemoveSequence(name, schema);
=> Sequence.RemoveSequence((IMutableModel)Check.NotNull(model, nameof(model)), name, schema);

/// <summary>
/// Returns all <see cref="ISequence" />s contained in the model.
/// </summary>
/// <param name="model"> The model to get the sequences in. </param>
public static IEnumerable<ISequence> GetSequences([NotNull] this IModel model)
=> Sequence.GetSequences(model);
=> Sequence.GetSequences(Check.NotNull(model, nameof(model)));

/// <summary>
/// Returns all <see cref="IMutableSequence" />s contained in the model.
/// </summary>
/// <param name="model"> The model to get the sequences in. </param>
public static IEnumerable<IMutableSequence> GetSequences([NotNull] this IMutableModel model)
=> (IEnumerable<IMutableSequence>)((IModel)model).GetSequences();
=> Sequence.GetSequences(Check.NotNull(model, nameof(model)));

/// <summary>
/// Returns all <see cref="IConventionSequence" />s contained in the model.
/// </summary>
/// <param name="model"> The model to get the sequences in. </param>
public static IEnumerable<IConventionSequence> GetSequences([NotNull] this IConventionModel model)
=> (IEnumerable<IConventionSequence>)((IModel)model).GetSequences();
=> Sequence.GetSequences(Check.NotNull(model, nameof(model)));

/// <summary>
/// Finds a <see cref="IDbFunction" /> that is mapped to the method represented by the given <see cref="MethodInfo" />.
Expand All @@ -263,14 +263,9 @@ public static IEnumerable<IConventionSequence> GetSequences([NotNull] this IConv
/// <param name="method"> The <see cref="MethodInfo" /> for the method that is mapped to the function. </param>
/// <returns> The <see cref="IDbFunction" /> or <c>null</c> if the method is not mapped. </returns>
public static IDbFunction FindDbFunction([NotNull] this IModel model, [NotNull] MethodInfo method)
{
Check.NotNull(model, nameof(model));
Check.NotNull(method, nameof(method));

return DbFunction.FindDbFunction(
=> DbFunction.FindDbFunction(
Check.NotNull(model, nameof(model)),
Check.NotNull(method, nameof(method)));
}

/// <summary>
/// Finds a <see cref="IMutableDbFunction" /> that is mapped to the method represented by the given <see cref="MethodInfo" />.
Expand All @@ -290,6 +285,35 @@ public static IMutableDbFunction FindDbFunction([NotNull] this IMutableModel mod
public static IConventionDbFunction FindDbFunction([NotNull] this IConventionModel model, [NotNull] MethodInfo method)
=> (IConventionDbFunction)((IModel)model).FindDbFunction(method);

/// <summary>
/// Finds a <see cref="IDbFunction" /> that is mapped to the method represented by the given <see cref="MethodInfo" />.
/// </summary>
/// <param name="model"> The model to find the function in. </param>
/// <param name="name"> The model name of the function. </param>
/// <returns> The <see cref="IDbFunction" /> or <c>null</c> if the method is not mapped. </returns>
public static IDbFunction FindDbFunction([NotNull] this IModel model, [NotNull] string name)
=> DbFunction.FindDbFunction(
Check.NotNull(model, nameof(model)),
Check.NotNull(name, nameof(name)));

/// <summary>
/// Finds a <see cref="IMutableDbFunction" /> that is mapped to the method represented by the given <see cref="MethodInfo" />.
/// </summary>
/// <param name="model"> The model to find the function in. </param>
/// <param name="name"> The model name of the function. </param>
/// <returns> The <see cref="IMutableDbFunction" /> or <c>null</c> if the method is not mapped. </returns>
public static IMutableDbFunction FindDbFunction([NotNull] this IMutableModel model, [NotNull] string name)
=> (IMutableDbFunction)((IModel)model).FindDbFunction(name);

/// <summary>
/// Finds a <see cref="IConventionDbFunction" /> that is mapped to the method represented by the given <see cref="MethodInfo" />.
/// </summary>
/// <param name="model"> The model to find the function in. </param>
/// <param name="name"> The model name of the function. </param>
/// <returns> The <see cref="IConventionDbFunction" /> or <c>null</c> if the method is not mapped. </returns>
public static IConventionDbFunction FindDbFunction([NotNull] this IConventionModel model, [NotNull] string name)
=> (IConventionDbFunction)((IModel)model).FindDbFunction(name);

/// <summary>
/// Either returns the existing <see cref="DbFunction" /> mapped to the given method
/// or creates a new function mapped to the method.
Expand All @@ -298,8 +322,8 @@ public static IConventionDbFunction FindDbFunction([NotNull] this IConventionMod
/// <param name="methodInfo"> The <see cref="MethodInfo" /> for the method that is mapped to the function. </param>
/// <returns> The <see cref="DbFunction" />. </returns>
public static DbFunction AddDbFunction([NotNull] this IMutableModel model, [NotNull] MethodInfo methodInfo)
=> new DbFunction(
Check.NotNull(methodInfo, nameof(methodInfo)), model, ConfigurationSource.Explicit);
=> DbFunction.AddDbFunction(
model, Check.NotNull(methodInfo, nameof(methodInfo)), ConfigurationSource.Explicit);

/// <summary>
/// Either returns the existing <see cref="DbFunction" /> mapped to the given method
Expand All @@ -311,9 +335,34 @@ public static DbFunction AddDbFunction([NotNull] this IMutableModel model, [NotN
/// <returns> The <see cref="DbFunction" />. </returns>
public static IConventionDbFunction AddDbFunction(
[NotNull] this IConventionModel model, [NotNull] MethodInfo methodInfo, bool fromDataAnnotation = false)
=> new DbFunction(
Check.NotNull(methodInfo, nameof(methodInfo)), (IMutableModel)model,
fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
=> DbFunction.AddDbFunction(
(IMutableModel)model, Check.NotNull(methodInfo, nameof(methodInfo)),
fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);

/// <summary>
/// Either returns the existing <see cref="DbFunction" /> mapped to the given method
/// or creates a new function mapped to the method.
/// </summary>
/// <param name="model"> The model to add the function to. </param>
/// <param name="name"> The model name of the function. </param>
/// <returns> The <see cref="DbFunction" />. </returns>
public static DbFunction AddDbFunction([NotNull] this IMutableModel model, [NotNull] string name)
=> DbFunction.AddDbFunction(
model, Check.NotNull(name, nameof(name)), ConfigurationSource.Explicit);

/// <summary>
/// Either returns the existing <see cref="DbFunction" /> mapped to the given method
/// or creates a new function mapped to the method.
/// </summary>
/// <param name="model"> The model to add the function to. </param>
/// <param name="name"> The model name of the function. </param>
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
/// <returns> The <see cref="DbFunction" />. </returns>
public static IConventionDbFunction AddDbFunction(
[NotNull] this IConventionModel model, [NotNull] string name, bool fromDataAnnotation = false)
=> DbFunction.AddDbFunction(
(IMutableModel)model, Check.NotNull(name, nameof(name)),
fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);

/// <summary>
/// Removes the <see cref="IMutableDbFunction" /> that is mapped to the method represented by the given
Expand All @@ -323,14 +372,9 @@ public static IConventionDbFunction AddDbFunction(
/// <param name="method"> The <see cref="MethodInfo" /> for the method that is mapped to the function. </param>
/// <returns> The removed <see cref="IMutableDbFunction" /> or <c>null</c> if the method is not mapped. </returns>
public static IMutableDbFunction RemoveDbFunction([NotNull] this IMutableModel model, [NotNull] MethodInfo method)
{
Check.NotNull(model, nameof(model));
Check.NotNull(method, nameof(method));

return DbFunction.RemoveDbFunction(
=> DbFunction.RemoveDbFunction(
Check.NotNull(model, nameof(model)),
Check.NotNull(method, nameof(method)));
}

/// <summary>
/// Removes the <see cref="IConventionDbFunction" /> that is mapped to the method represented by the given
Expand All @@ -342,25 +386,47 @@ public static IMutableDbFunction RemoveDbFunction([NotNull] this IMutableModel m
public static IConventionDbFunction RemoveDbFunction([NotNull] this IConventionModel model, [NotNull] MethodInfo method)
=> (IConventionDbFunction)((IMutableModel)model).RemoveDbFunction(method);

/// <summary>
/// Removes the <see cref="IMutableDbFunction" /> that is mapped to the method represented by the given
/// <see cref="MethodInfo" />.
/// </summary>
/// <param name="model"> The model to find the function in. </param>
/// <param name="name"> The model name of the function. </param>
/// <returns> The removed <see cref="IMutableDbFunction" /> or <c>null</c> if the method is not mapped. </returns>
public static IMutableDbFunction RemoveDbFunction([NotNull] this IMutableModel model, [NotNull] string name)
=> DbFunction.RemoveDbFunction(
Check.NotNull(model, nameof(model)),
Check.NotNull(name, nameof(name)));

/// <summary>
/// Removes the <see cref="IConventionDbFunction" /> that is mapped to the method represented by the given
/// <see cref="MethodInfo" />.
/// </summary>
/// <param name="model"> The model to find the function in. </param>
/// <param name="name"> The model name of the function. </param>
/// <returns> The removed <see cref="IConventionDbFunction" /> or <c>null</c> if the method is not mapped. </returns>
public static IConventionDbFunction RemoveDbFunction([NotNull] this IConventionModel model, [NotNull] string name)
=> (IConventionDbFunction)((IMutableModel)model).RemoveDbFunction(name);

/// <summary>
/// Returns all <see cref="IDbFunction" />s contained in the model.
/// </summary>
/// <param name="model"> The model to get the functions in. </param>
public static IEnumerable<IDbFunction> GetDbFunctions([NotNull] this IModel model)
=> DbFunction.GetDbFunctions(model.AsModel());
=> DbFunction.GetDbFunctions(Check.NotNull(model, nameof(model)));

/// <summary>
/// Returns all <see cref="IMutableDbFunction" />s contained in the model.
/// </summary>
/// <param name="model"> The model to get the functions in. </param>
public static IEnumerable<IMutableDbFunction> GetDbFunctions([NotNull] this IMutableModel model)
=> DbFunction.GetDbFunctions((Model)model);
=> DbFunction.GetDbFunctions((Model)Check.NotNull(model, nameof(model)));

/// <summary>
/// Returns all <see cref="IConventionDbFunction" />s contained in the model.
/// </summary>
/// <param name="model"> The model to get the functions in. </param>
public static IEnumerable<IConventionDbFunction> GetDbFunctions([NotNull] this IConventionModel model)
=> DbFunction.GetDbFunctions((Model)model);
=> DbFunction.GetDbFunctions((Model)Check.NotNull(model, nameof(model)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ public override ConventionSet CreateConventionSet()

var dbFunctionAttributeConvention = new RelationalDbFunctionAttributeConvention(Dependencies, RelationalDependencies);
conventionSet.ModelInitializedConventions.Add(dbFunctionAttributeConvention);
conventionSet.ModelAnnotationChangedConventions.Add(dbFunctionAttributeConvention);

conventionSet.ModelFinalizingConventions.Add(dbFunctionAttributeConvention);
conventionSet.ModelFinalizingConventions.Add(tableNameFromDbSetConvention);
conventionSet.ModelFinalizingConventions.Add(storeGenerationConvention);
conventionSet.ModelFinalizingConventions.Add(new SharedTableConvention(Dependencies, RelationalDependencies));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
// 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.Linq;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
using Microsoft.EntityFrameworkCore.Utilities;

namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
{
/// <summary>
/// A convention that configures model function mappings based on public static methods on the context marked with
/// <see cref="DbFunctionAttribute" />.
/// </summary>
public class RelationalDbFunctionAttributeConvention : IModelInitializedConvention, IModelAnnotationChangedConvention
public class RelationalDbFunctionAttributeConvention : IModelInitializedConvention, IModelFinalizingConvention
{
/// <summary>
/// Creates a new instance of <see cref="RelationalDbFunctionAttributeConvention" />.
Expand Down Expand Up @@ -63,29 +61,12 @@ public virtual void ProcessModelInitialized(
}
}

/// <summary>
/// Called after an annotation is changed on an model.
/// </summary>
/// <param name="modelBuilder"> The builder for the model. </param>
/// <param name="name"> The annotation name. </param>
/// <param name="annotation"> The new annotation. </param>
/// <param name="oldAnnotation"> The old annotation. </param>
/// <param name="context"> Additional information associated with convention execution. </param>
public virtual void ProcessModelAnnotationChanged(
IConventionModelBuilder modelBuilder,
string name,
IConventionAnnotation annotation,
IConventionAnnotation oldAnnotation,
IConventionContext<IConventionAnnotation> context)
/// <inheritdoc />
public virtual void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, IConventionContext<IConventionModelBuilder> context)
{
Check.NotNull(modelBuilder, nameof(modelBuilder));
Check.NotNull(name, nameof(name));

if (name.StartsWith(RelationalAnnotationNames.DbFunction, StringComparison.Ordinal)
&& annotation?.Value != null
&& oldAnnotation == null)
foreach (var function in modelBuilder.Metadata.GetDbFunctions())
{
ProcessDbFunctionAdded(new DbFunctionBuilder((IMutableDbFunction)annotation.Value), context);
ProcessDbFunctionAdded(function.Builder, context);
}
}

Expand All @@ -98,10 +79,15 @@ protected virtual void ProcessDbFunctionAdded(
[NotNull] IConventionDbFunctionBuilder dbFunctionBuilder, [NotNull] IConventionContext context)
{
var methodInfo = dbFunctionBuilder.Metadata.MethodInfo;
var dbFunctionAttribute = methodInfo.GetCustomAttributes<DbFunctionAttribute>().SingleOrDefault();

dbFunctionBuilder.HasName(dbFunctionAttribute?.Name ?? methodInfo.Name);
dbFunctionBuilder.HasSchema(dbFunctionAttribute?.Schema);
var dbFunctionAttribute = methodInfo?.GetCustomAttributes<DbFunctionAttribute>().SingleOrDefault();
if (dbFunctionAttribute != null)
{
dbFunctionBuilder.HasName(dbFunctionAttribute.Name, fromDataAnnotation: true);
if (dbFunctionAttribute.Schema != null)
{
dbFunctionBuilder.HasSchema(dbFunctionAttribute.Schema, fromDataAnnotation: true);
}
}
}
}
}
Loading