-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Take 2 - Add support for user defined scalar functions #8507
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
Merged
+3,114
−187
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
...lational.Specification.Tests/TestModels/NorthwindDbFunction/NorthwindDbFunctionContext.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// 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 Microsoft.EntityFrameworkCore.Metadata; | ||
using Microsoft.EntityFrameworkCore.TestModels.Northwind; | ||
|
||
namespace Microsoft.EntityFrameworkCore | ||
{ | ||
public class NorthwindDbFunctionContext : NorthwindContext | ||
{ | ||
public NorthwindDbFunctionContext(DbContextOptions options, QueryTrackingBehavior queryTrackingBehavior = QueryTrackingBehavior.TrackAll) | ||
: base(options, queryTrackingBehavior) | ||
{ | ||
} | ||
|
||
public enum ReportingPeriod | ||
{ | ||
Winter = 0, | ||
Spring, | ||
Summer, | ||
Fall | ||
} | ||
|
||
public static int MyCustomLength(string s) | ||
{ | ||
throw new Exception(); | ||
} | ||
|
||
[DbFunction(Schema = "dbo", Name = "EmployeeOrderCount")] | ||
public static int EmployeeOrderCount(int employeeId) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
[DbFunction(Schema = "dbo", Name = "EmployeeOrderCount")] | ||
public static int EmployeeOrderCountWithClient(int employeeId) | ||
{ | ||
switch (employeeId) | ||
{ | ||
case 3: return 127; | ||
default: return 1; | ||
} | ||
} | ||
|
||
[DbFunction(Schema = "dbo")] | ||
public static bool IsTopEmployee(int employeeId) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
[DbFunction(Schema = "dbo")] | ||
public static int GetEmployeeWithMostOrdersAfterDate(DateTime? startDate) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
[DbFunction(Schema = "dbo")] | ||
public static DateTime? GetReportingPeriodStartDate(ReportingPeriod periodId) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
[DbFunction(Schema = "dbo")] | ||
public static string StarValue(int starCount, int value) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
[DbFunction(Name = "StarValue", Schema = "dbo")] | ||
public static string StarValueAlternateParamOrder([DbFunctionParameter(ParameterIndex = 1)]int value, [DbFunctionParameter(ParameterIndex = 0)]int starCount) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
[DbFunction(Schema = "dbo")] | ||
public static int AddValues(int a, int b) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
[DbFunction(Schema = "dbo")] | ||
public static DateTime GetBestYearEver() | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
src/EFCore.Relational/Infrastructure/RelationalModelCustomizer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// 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.Linq; | ||
using System.Reflection; | ||
using JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Internal; | ||
using Microsoft.EntityFrameworkCore.Metadata; | ||
using Microsoft.EntityFrameworkCore.Metadata.Internal; | ||
using Microsoft.EntityFrameworkCore.Utilities; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Infrastructure | ||
{ | ||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public class RelationalModelCustomizer : ModelCustomizer | ||
{ | ||
public RelationalModelCustomizer([NotNull] ModelCustomizerDependencies dependencies) | ||
: base(dependencies) | ||
{ | ||
} | ||
|
||
public override void Customize(ModelBuilder modelBuilder, DbContext dbContext) | ||
{ | ||
FindDbFunctions(modelBuilder, dbContext); | ||
|
||
base.Customize(modelBuilder, dbContext); | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
protected virtual void FindDbFunctions([NotNull] ModelBuilder modelBuilder, [NotNull] DbContext context) | ||
{ | ||
Check.NotNull(modelBuilder, nameof(modelBuilder)); | ||
Check.NotNull(context, nameof(context)); | ||
|
||
var functions = context.GetType().GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy) | ||
.Where(mi => mi.IsStatic | ||
&& mi.IsPublic | ||
&& mi.GetCustomAttributes(typeof(DbFunctionAttribute)).Any()); | ||
|
||
foreach (var function in functions) | ||
{ | ||
modelBuilder.HasDbFunction(function); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
protected override void FindSets(ModelBuilder modelBuilder, DbContext context) | ||
{ | ||
base.FindSets(modelBuilder, context); | ||
|
||
var sets = Dependencies.SetFinder.CreateClrTypeDbSetMapping(context); | ||
|
||
foreach (var entityType in modelBuilder.Model.GetEntityTypes().Cast<EntityType>()) | ||
{ | ||
if (entityType.BaseType == null | ||
&& sets.ContainsKey(entityType.ClrType)) | ||
{ | ||
entityType.Builder.Relational(ConfigurationSource.Convention).ToTable(sets[entityType.ClrType].Name); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
src/EFCore.Relational/Metadata/Conventions/Internal/RelationalDbFunctionConvention.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// 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 Microsoft.EntityFrameworkCore.Infrastructure; | ||
using Microsoft.EntityFrameworkCore.Metadata.Internal; | ||
using Microsoft.EntityFrameworkCore.Utilities; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal | ||
{ | ||
public class RelationalDbFunctionConvention : IModelAnnotationChangedConvention | ||
{ | ||
public virtual Annotation Apply(InternalModelBuilder modelBuilder, string name, Annotation annotation, Annotation oldAnnotation) | ||
{ | ||
Check.NotNull(modelBuilder, nameof(modelBuilder)); | ||
Check.NotNull(name, nameof(name)); | ||
|
||
if (name.StartsWith(RelationalAnnotationNames.DbFunction, StringComparison.OrdinalIgnoreCase) | ||
&& annotation != null | ||
&& oldAnnotation == null) | ||
{ | ||
var dbFunctionBuilder = new InternalDbFunctionBuilder((DbFunction)annotation.Value); | ||
|
||
var dbFuncMethodInfo = dbFunctionBuilder.Metadata.MethodInfo; | ||
|
||
var dbFuncAttribute = dbFuncMethodInfo.GetCustomAttributes<DbFunctionAttribute>().SingleOrDefault(); | ||
|
||
dbFunctionBuilder.HasName(dbFuncAttribute?.Name ?? dbFuncMethodInfo.Name, ConfigurationSource.Convention); | ||
dbFunctionBuilder.HasSchema(dbFuncAttribute?.Schema ?? modelBuilder.Metadata.Relational().DefaultSchema, ConfigurationSource.Convention); | ||
|
||
var parameters = dbFuncMethodInfo.GetParameters() | ||
.Where(p => p.ParameterType != typeof(DbFunctions)) | ||
.Select((pi, i) => new | ||
{ | ||
ParameterIndex = i, | ||
ParameterInfo = pi, | ||
DbFuncParamAttr = pi.GetCustomAttributes<DbFunctionParameterAttribute>().SingleOrDefault(), | ||
pi.ParameterType | ||
}); | ||
|
||
foreach (var p in parameters) | ||
{ | ||
var paramBuilder = dbFunctionBuilder.HasParameter(p.ParameterInfo.Name, ConfigurationSource.Convention); | ||
|
||
paramBuilder.HasIndex(p.DbFuncParamAttr?.ParameterIndex ?? p.ParameterIndex, ConfigurationSource.Convention); | ||
paramBuilder.HasType(p.ParameterType, ConfigurationSource.Convention); | ||
} | ||
} | ||
|
||
return annotation; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// 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 JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Utilities; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata | ||
{ | ||
/// <summary> | ||
/// Defines a user defined database function | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Method)] | ||
public sealed class DbFunctionAttribute : Attribute | ||
{ | ||
private string _name; | ||
|
||
/// <summary> | ||
/// Defines a user defined database function | ||
/// </summary> | ||
public DbFunctionAttribute() | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Defines a user defined database function | ||
/// </summary> | ||
/// <param name="name">The name of the function in the underlying datastore.</param> | ||
/// <param name="schema">The schema where the function lives in the underlying datastore.</param> | ||
public DbFunctionAttribute([NotNull] string name, [CanBeNull] string schema) | ||
{ | ||
Check.NotEmpty(name, nameof(name)); | ||
|
||
Schema = schema; | ||
Name = name; | ||
} | ||
|
||
/// <summary> | ||
/// The name of the function in the underlying datastore. | ||
/// </summary> | ||
public string Name | ||
{ | ||
get { return _name; } | ||
|
||
[param: NotNull] | ||
set | ||
{ | ||
Check.NotNull(value, nameof(Name)); | ||
_name = value; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// The schema where the function lives in the underlying datastore. | ||
/// </summary> | ||
public string Schema { get; [param: CanBeNull] set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
// 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.Collections.Generic; | ||
using System.Linq.Expressions; | ||
using JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Metadata.Internal; | ||
using Microsoft.EntityFrameworkCore.Query.Expressions; | ||
using Microsoft.EntityFrameworkCore.Utilities; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata | ||
{ | ||
/// <summary> | ||
/// <para> | ||
/// Provides a simple API for configuring a <see cref="Metadata" />. | ||
/// </para> | ||
/// <para> | ||
/// Instances of this class are returned from methods when using the <see cref="ModelBuilder" /> API | ||
/// and it is not designed to be directly constructed in your application code. | ||
/// </para> | ||
/// </summary> | ||
/// | ||
public class DbFunctionBuilder | ||
{ | ||
private readonly InternalDbFunctionBuilder _builder; | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public DbFunctionBuilder([NotNull] DbFunction dbFunction) | ||
{ | ||
Check.NotNull(dbFunction, nameof(dbFunction)); | ||
|
||
_builder = new InternalDbFunctionBuilder(dbFunction); | ||
} | ||
|
||
public virtual IMutableDbFunction Metadata => _builder.Metadata; | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual DbFunctionBuilder HasSchema([CanBeNull]string schema) | ||
{ | ||
_builder.HasSchema(schema, ConfigurationSource.Explicit); | ||
|
||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual DbFunctionBuilder HasName([NotNull] string name) | ||
{ | ||
Check.NotNull(name, nameof(name)); | ||
|
||
_builder.HasName(name, ConfigurationSource.Explicit); | ||
|
||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual DbFunctionParameterBuilder HasParameter([NotNull] string name) | ||
{ | ||
Check.NotNull(name, nameof(name)); | ||
|
||
return new DbFunctionParameterBuilder(_builder.HasParameter(name, ConfigurationSource.Explicit)); | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual DbFunctionBuilder HasReturnType([NotNull] Type returnType) | ||
{ | ||
Check.NotNull(returnType, nameof(returnType)); | ||
|
||
_builder.HasReturnType(returnType, ConfigurationSource.Explicit); | ||
|
||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual DbFunctionBuilder TranslateWith([NotNull] Func<IReadOnlyCollection<Expression>, IDbFunction, SqlFunctionExpression> translateCallback) | ||
{ | ||
Check.NotNull(translateCallback, nameof(translateCallback)); | ||
|
||
_builder.TranslateWith(translateCallback); | ||
|
||
return this; | ||
} | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/EFCore.Relational/Metadata/DbFunctionParameterAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// 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 JetBrains.Annotations; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata | ||
{ | ||
/// <summary> | ||
/// Define a parameter for a user defined database function | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Parameter)] | ||
public sealed class DbFunctionParameterAttribute : Attribute | ||
{ | ||
/// <summary> | ||
/// Sets the index order for this parameter on the parent function | ||
/// </summary> | ||
public int ParameterIndex { get; [param: NotNull] set; } | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
src/EFCore.Relational/Metadata/DbFunctionParameterBuilder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// 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 JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Metadata.Internal; | ||
using Microsoft.EntityFrameworkCore.Utilities; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata | ||
{ | ||
/// <summary> | ||
/// <para> | ||
/// Provides a simple API for configuring an <see cref="DbFunctionParameter" />. | ||
/// </para> | ||
/// <para> | ||
/// Instances of this class are returned from methods when using the <see cref="ModelBuilder" /> API | ||
/// and it is not designed to be directly constructed in your application code. | ||
/// </para> | ||
/// </summary> | ||
public class DbFunctionParameterBuilder | ||
{ | ||
private readonly InternalDbFunctionParameterBuilder _builder; | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public DbFunctionParameterBuilder([NotNull] DbFunctionParameter dbFunctionParameter) | ||
{ | ||
Check.NotNull(dbFunctionParameter, nameof(dbFunctionParameter)); | ||
|
||
_builder = new InternalDbFunctionParameterBuilder(dbFunctionParameter); | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public DbFunctionParameterBuilder([NotNull] InternalDbFunctionParameterBuilder builder) | ||
{ | ||
Check.NotNull(builder, nameof(builder)); | ||
|
||
_builder = builder; | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual IMutableDbFunctionParameter Metadata => _builder.Parameter; | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual DbFunctionParameterBuilder HasIndex(int index) | ||
{ | ||
_builder.HasIndex(index, ConfigurationSource.Explicit); | ||
|
||
return this; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// 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.Collections.Generic; | ||
using System.Reflection; | ||
using System.Linq.Expressions; | ||
using Microsoft.EntityFrameworkCore.Metadata.Internal; | ||
using Microsoft.EntityFrameworkCore.Query.Expressions; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata | ||
{ | ||
/// <summary> | ||
/// Represents a db function in an <see cref="IModel" />. | ||
/// </summary> | ||
public interface IDbFunction | ||
{ | ||
/// <summary> | ||
/// The schema where the function lives in the underlying datastore. | ||
/// </summary> | ||
string Schema { get; } | ||
|
||
/// <summary> | ||
/// The name of the function in the underlying datastore. | ||
/// </summary> | ||
string Name { get; } | ||
|
||
/// <summary> | ||
/// The list of parameters which are passed to the underlying datastores function. | ||
/// </summary> | ||
IReadOnlyList<DbFunctionParameter> Parameters { get; } | ||
|
||
/// <summary> | ||
/// The .Net method which maps to the function in the underlying datastore | ||
/// </summary> | ||
MethodInfo MethodInfo { get; } | ||
|
||
/// <summary> | ||
/// The return type of the mapped .Net method | ||
/// </summary> | ||
Type ReturnType { get; } | ||
|
||
/// <summary> | ||
/// A translate callback for converting a method call into a sql function | ||
/// </summary> | ||
Func<IReadOnlyCollection<Expression>, IDbFunction, SqlFunctionExpression> TranslateCallback { get; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// 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; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata | ||
{ | ||
/// <summary> | ||
/// Represents a db function parameter in an <see cref="IDbFunction" />. | ||
/// </summary> | ||
public interface IDbFunctionParameter | ||
{ | ||
/// <summary> | ||
/// The name of the parameter on the .Net method. | ||
/// </summary> | ||
string Name { get; } | ||
|
||
/// <summary> | ||
/// The index of the parameter on the mapped datastore method. | ||
/// </summary> | ||
int Index { get; } | ||
|
||
/// <summary> | ||
/// The .Net parameter type. | ||
/// </summary> | ||
Type ParameterType { get; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// 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.Collections.Generic; | ||
using System.Linq.Expressions; | ||
using JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Metadata.Internal; | ||
using Microsoft.EntityFrameworkCore.Query.Expressions; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata | ||
{ | ||
public interface IMutableDbFunction : IDbFunction | ||
{ | ||
/// <summary> | ||
/// The schema where the function lives in the underlying datastore. | ||
/// </summary> | ||
new string Schema { get; [param: CanBeNull] set; } | ||
|
||
/// <summary> | ||
/// The name of the function in the underlying datastore. | ||
/// </summary> | ||
new string Name { get; [param: NotNull] set;} | ||
|
||
/// <summary> | ||
/// The return type of the mapped .Net method | ||
/// </summary> | ||
new Type ReturnType { get; [param: NotNull] set;} | ||
|
||
/// <summary> | ||
/// A translate callback for converting a method call into a sql function | ||
/// </summary> | ||
new Func<IReadOnlyCollection<Expression>, IDbFunction, SqlFunctionExpression> TranslateCallback { get; [param: CanBeNull] set; } | ||
|
||
/// <summary> | ||
/// Add a dbFunctionParameter to this DbFunction | ||
/// </summary> | ||
DbFunctionParameter AddParameter([NotNull] string name); | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/EFCore.Relational/Metadata/IMutableDbFunctionParameter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// 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 JetBrains.Annotations; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata | ||
{ | ||
/// <summary> | ||
/// Represents a db function parameter in an <see cref="IDbFunction" />. | ||
/// </summary> | ||
public interface IMutableDbFunctionParameter : IDbFunctionParameter | ||
{ | ||
/// <summary> | ||
/// The name of the parameter on the .Net method. | ||
/// </summary> | ||
new string Name { get; [param: NotNull] set; } | ||
|
||
/// <summary> | ||
/// The index of the parameter on the mapped datastore method. | ||
/// </summary> | ||
new int Index { get; set; } | ||
|
||
/// <summary> | ||
/// The .Net parameter type. | ||
/// </summary> | ||
new Type ParameterType { get; [param: NotNull] set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
// 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.Collections.Generic; | ||
using System.Collections.ObjectModel; | ||
using System.Linq; | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
using JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Internal; | ||
using Microsoft.EntityFrameworkCore.Utilities; | ||
using Microsoft.EntityFrameworkCore.Query.ExpressionTranslators; | ||
using Microsoft.EntityFrameworkCore.Query.Expressions; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata.Internal | ||
{ | ||
/// <summary> | ||
/// Represents a db function in an <see cref="IModel" />. | ||
/// </summary> | ||
public class DbFunction : IMutableDbFunction, IMethodCallTranslator | ||
{ | ||
private readonly SortedDictionary<string, DbFunctionParameter> _parameters | ||
= new SortedDictionary<string, DbFunctionParameter>(StringComparer.OrdinalIgnoreCase); | ||
|
||
private string _schema; | ||
private string _name; | ||
private Type _returnType; | ||
|
||
private ConfigurationSource? _schemaConfigurationSource; | ||
private ConfigurationSource? _nameConfigurationSource; | ||
private ConfigurationSource? _returnTypeConfigurationSource; | ||
|
||
private DbFunction([NotNull] MethodInfo dbFunctionMethodInfo, | ||
[NotNull] IMutableModel model, | ||
[NotNull] string annotationPrefix, | ||
[CanBeNull] string name, | ||
[CanBeNull] string schema, | ||
ConfigurationSource configurationSource) | ||
{ | ||
Check.NotNull(dbFunctionMethodInfo, nameof(dbFunctionMethodInfo)); | ||
Check.NotNull(model, nameof(model)); | ||
Check.NotNull(annotationPrefix, nameof(annotationPrefix)); | ||
|
||
if (dbFunctionMethodInfo.IsGenericMethod) | ||
throw new ArgumentException(CoreStrings.DbFunctionGenericMethodNotSupported(dbFunctionMethodInfo)); | ||
|
||
if (name != null) | ||
_nameConfigurationSource = configurationSource; | ||
|
||
if (schema != null) | ||
_schemaConfigurationSource = configurationSource; | ||
|
||
_returnTypeConfigurationSource = configurationSource; | ||
|
||
_name = name; | ||
_schema = schema; | ||
_returnType = dbFunctionMethodInfo.ReturnType; | ||
MethodInfo = dbFunctionMethodInfo; | ||
|
||
model[BuildAnnotationName(annotationPrefix, dbFunctionMethodInfo)] = this; | ||
} | ||
|
||
public static DbFunction GetOrAddDbFunction( | ||
[NotNull] IMutableModel model, | ||
[NotNull] MethodInfo methodInfo, | ||
[NotNull] string annotationPrefix, | ||
ConfigurationSource configurationSource, | ||
[CanBeNull] string name = null, | ||
[CanBeNull] string schema = null) | ||
=> FindDbFunction(model, annotationPrefix, methodInfo) | ||
?? new DbFunction(methodInfo, model, annotationPrefix, name, schema, configurationSource); | ||
|
||
public static DbFunction FindDbFunction([NotNull] IModel model, | ||
[NotNull] string annotationPrefix, | ||
[NotNull] MethodInfo methodInfo) | ||
{ | ||
Check.NotNull(model, nameof(model)); | ||
Check.NotNull(annotationPrefix, nameof(annotationPrefix)); | ||
Check.NotNull(methodInfo, nameof(methodInfo)); | ||
|
||
return model[BuildAnnotationName(annotationPrefix, methodInfo)] as DbFunction; | ||
} | ||
|
||
public static IEnumerable<IDbFunction> GetDbFunctions([NotNull] IModel model, [NotNull] string annotationPrefix) | ||
{ | ||
Check.NotNull(model, nameof(model)); | ||
Check.NotEmpty(annotationPrefix, nameof(annotationPrefix)); | ||
|
||
return model.GetAnnotations() | ||
.Where(a => a.Name.StartsWith(annotationPrefix, StringComparison.Ordinal)) | ||
.Select(a => a.Value) | ||
.Cast<IDbFunction>(); | ||
} | ||
|
||
private static string BuildAnnotationName(string annotationPrefix, MethodInfo methodInfo) | ||
=> $@"{annotationPrefix}{methodInfo.Name}({string.Join(",", methodInfo.GetParameters().Select(p => p.ParameterType.Name))})"; | ||
|
||
/// <summary> | ||
/// The schema where the function lives in the underlying datastore. | ||
/// </summary> | ||
public virtual string Schema | ||
{ | ||
get =>_schema; | ||
|
||
[param: CanBeNull] set => SetSchema(value, ConfigurationSource.Explicit); | ||
} | ||
|
||
public virtual void SetSchema([CanBeNull] string schema, ConfigurationSource configurationSource) | ||
{ | ||
_schema = schema; | ||
UpdateSchemaConfigurationSource(configurationSource); | ||
} | ||
|
||
private void UpdateSchemaConfigurationSource(ConfigurationSource configurationSource) | ||
=> _schemaConfigurationSource = configurationSource.Max(_schemaConfigurationSource); | ||
|
||
public virtual ConfigurationSource? GetSchemaConfigurationSource() => _schemaConfigurationSource; | ||
|
||
/// <summary> | ||
/// The name of the function in the underlying datastore. | ||
/// </summary> | ||
public virtual string Name | ||
{ | ||
get => _name; | ||
|
||
[param: NotNull] set => SetName(value, ConfigurationSource.Explicit); | ||
} | ||
|
||
public virtual void SetName([NotNull] string name, ConfigurationSource configurationSource) | ||
{ | ||
Check.NotNull(name, nameof(name)); | ||
|
||
_name = name; | ||
UpdateNameConfigurationSource(configurationSource); | ||
} | ||
|
||
private void UpdateNameConfigurationSource(ConfigurationSource configurationSource) | ||
=> _nameConfigurationSource = configurationSource.Max(_nameConfigurationSource); | ||
|
||
public virtual ConfigurationSource? GetNameConfigurationSource() => _nameConfigurationSource; | ||
|
||
/// <summary> | ||
/// The return type of the mapped .Net method | ||
/// </summary> | ||
public virtual Type ReturnType | ||
{ | ||
get => _returnType; | ||
|
||
[param: NotNull] set => SetReturnType(value, ConfigurationSource.Explicit); | ||
} | ||
|
||
public virtual void SetReturnType([NotNull] Type returnType, ConfigurationSource configurationSource) | ||
{ | ||
Check.NotNull(returnType, nameof(returnType)); | ||
|
||
_returnType = returnType; | ||
UpdateReturnTypeConfigurationSource(configurationSource); | ||
} | ||
|
||
private void UpdateReturnTypeConfigurationSource(ConfigurationSource configurationSource) | ||
=> _returnTypeConfigurationSource = configurationSource.Max(_returnTypeConfigurationSource); | ||
|
||
public virtual ConfigurationSource? GetReturnTypeConfigurationSource() => _nameConfigurationSource; | ||
|
||
/// <summary> | ||
/// The list of parameters which are passed to the underlying datastores function. | ||
/// </summary> | ||
public virtual IReadOnlyList<DbFunctionParameter> Parameters => _parameters.Values.ToList(); | ||
|
||
/// <summary> | ||
/// The .Net method which maps to the function in the underlying datastore | ||
/// </summary> | ||
public virtual MethodInfo MethodInfo { get; } | ||
|
||
/// <summary> | ||
/// If set this callback is used to translate the .Net method call to a Linq Expression. | ||
/// </summary> | ||
public virtual Func<IReadOnlyCollection<Expression>, IDbFunction, SqlFunctionExpression> TranslateCallback { get; [param: CanBeNull] set; } | ||
|
||
public virtual DbFunctionParameter AddParameter(string name) | ||
=> AddParameter(name, ConfigurationSource.Explicit); | ||
|
||
public virtual DbFunctionParameter AddParameter([NotNull] string name, ConfigurationSource configurationSource) | ||
{ | ||
Check.NotNull(name, nameof(name)); | ||
|
||
var newParam = new DbFunctionParameter(name, configurationSource); | ||
|
||
_parameters.Add(newParam.Name, newParam); | ||
|
||
return newParam; | ||
} | ||
|
||
public virtual DbFunctionParameter FindParameter([NotNull] string name, ConfigurationSource configurationSource) | ||
{ | ||
Check.NotNull(name, nameof(name)); | ||
|
||
DbFunctionParameter parameter; | ||
|
||
if(_parameters.TryGetValue(name, out parameter)) | ||
parameter.UpdateConfigurationSource(configurationSource); | ||
|
||
return parameter; | ||
} | ||
|
||
Expression IMethodCallTranslator.Translate(MethodCallExpression methodCallExpression) | ||
{ | ||
Check.NotNull(methodCallExpression, nameof(methodCallExpression)); | ||
|
||
var methodArgs = methodCallExpression.Method.GetParameters().Zip(methodCallExpression.Arguments, (p, a) => new { Parameter = p, Argument = a }); | ||
|
||
var arguments = new ReadOnlyCollection<Expression>( | ||
(from dbParam in Parameters | ||
join methodArg in methodArgs on dbParam.Name equals methodArg.Parameter.Name into passParams | ||
from passParam in passParams | ||
orderby dbParam.Index | ||
select passParam.Argument).ToList()); | ||
|
||
return TranslateCallback?.Invoke(arguments, this) | ||
?? new SqlFunctionExpression(Name, ReturnType, Schema, arguments); | ||
} | ||
} | ||
} |
92 changes: 92 additions & 0 deletions
92
src/EFCore.Relational/Metadata/Internal/DbFunctionParameter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// 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 JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Utilities; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata.Internal | ||
{ | ||
public class DbFunctionParameter : IMutableDbFunctionParameter | ||
{ | ||
private int _index; | ||
private Type _parameterType; | ||
private string _name; | ||
private ConfigurationSource? _parameterIndexConfigurationSource; | ||
private ConfigurationSource? _parameterTypeConfigurationSource; | ||
private ConfigurationSource? _nameConfigurationSource; | ||
private ConfigurationSource _configurationSource; | ||
|
||
public DbFunctionParameter([NotNull] string name, ConfigurationSource configurationSource) | ||
{ | ||
Check.NotEmpty(name, nameof(name)); | ||
|
||
_name = name; | ||
_configurationSource = configurationSource; | ||
_nameConfigurationSource = configurationSource; | ||
} | ||
|
||
public virtual void UpdateConfigurationSource(ConfigurationSource configurationSource) | ||
=> _configurationSource = configurationSource.Max(_configurationSource); | ||
|
||
public virtual ConfigurationSource? GetConfigurationSource() => _configurationSource; | ||
|
||
public virtual string Name | ||
{ | ||
get => _name; | ||
[param: NotNull] set => SetName(value, ConfigurationSource.Explicit); | ||
} | ||
|
||
public virtual void SetName([NotNull] string name, ConfigurationSource configSource) | ||
{ | ||
Check.NotNull(name, nameof(name)); | ||
|
||
UpdateNameConfigurationSource(configSource); | ||
|
||
_name = name; | ||
} | ||
|
||
private void UpdateNameConfigurationSource(ConfigurationSource configurationSource) | ||
=> _nameConfigurationSource = configurationSource.Max(_nameConfigurationSource); | ||
|
||
public virtual ConfigurationSource? GetNameConfigurationSource() => _nameConfigurationSource; | ||
|
||
public virtual Type ParameterType | ||
{ | ||
get => _parameterType; | ||
[param: NotNull] set => SetParameterType(value, ConfigurationSource.Explicit); | ||
} | ||
|
||
private void UpdateParameterTypeConfigurationSource(ConfigurationSource configurationSource) | ||
=> _parameterTypeConfigurationSource = configurationSource.Max(_parameterTypeConfigurationSource); | ||
|
||
public virtual ConfigurationSource? GetParameterTypeConfigurationSource() => _parameterTypeConfigurationSource; | ||
|
||
public virtual void SetParameterType([NotNull] Type parameterType, ConfigurationSource configSource) | ||
{ | ||
Check.NotNull(parameterType, nameof(parameterType)); | ||
|
||
UpdateParameterTypeConfigurationSource(configSource); | ||
|
||
_parameterType = parameterType; | ||
} | ||
|
||
public virtual int Index | ||
{ | ||
get => _index; | ||
set => SetParameterIndex(value, ConfigurationSource.Explicit); | ||
} | ||
|
||
private void UpdateParameterIndexConfigurationSource(ConfigurationSource configurationSource) | ||
=> _parameterIndexConfigurationSource = configurationSource.Max(_parameterIndexConfigurationSource); | ||
|
||
public virtual ConfigurationSource? GetParameterIndexConfigurationSource() => _parameterIndexConfigurationSource; | ||
|
||
public virtual void SetParameterIndex(int index, ConfigurationSource configSource) | ||
{ | ||
UpdateParameterIndexConfigurationSource(configSource); | ||
|
||
_index = index; | ||
} | ||
} | ||
} |
97 changes: 97 additions & 0 deletions
97
src/EFCore.Relational/Metadata/Internal/InternalDbFunctionBuilder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// 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.Collections.Generic; | ||
using System.Linq.Expressions; | ||
using JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Query.Expressions; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata.Internal | ||
{ | ||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public class InternalDbFunctionBuilder | ||
{ | ||
private readonly DbFunction _dbFunction; | ||
|
||
public InternalDbFunctionBuilder([NotNull] DbFunction dbFunction) | ||
{ | ||
_dbFunction = dbFunction; | ||
} | ||
|
||
public virtual IMutableDbFunction Metadata => _dbFunction; | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual InternalDbFunctionBuilder HasSchema([CanBeNull] string schema, ConfigurationSource configurationSource) | ||
{ | ||
if (configurationSource.Overrides(_dbFunction.GetSchemaConfigurationSource()) | ||
|| _dbFunction.Schema == schema) | ||
{ | ||
_dbFunction.SetSchema(schema, configurationSource); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual InternalDbFunctionBuilder HasName([NotNull] string name, ConfigurationSource configurationSource) | ||
{ | ||
if (configurationSource.Overrides(_dbFunction.GetNameConfigurationSource()) | ||
|| _dbFunction.Name == name) | ||
{ | ||
_dbFunction.SetName(name, configurationSource); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual InternalDbFunctionBuilder HasReturnType([NotNull] Type returnType, ConfigurationSource configurationSource) | ||
{ | ||
if (configurationSource.Overrides(_dbFunction.GetReturnTypeConfigurationSource()) | ||
|| _dbFunction.ReturnType == returnType) | ||
{ | ||
_dbFunction.SetReturnType(returnType, configurationSource); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual InternalDbFunctionParameterBuilder HasParameter([NotNull] string name, ConfigurationSource configurationSource) | ||
{ | ||
return new InternalDbFunctionParameterBuilder(GetOrCreateParameter(name, configurationSource)); | ||
} | ||
|
||
private DbFunctionParameter GetOrCreateParameter(string name, ConfigurationSource configurationSource) | ||
{ | ||
return _dbFunction.FindParameter(name, configurationSource) ?? _dbFunction.AddParameter(name, configurationSource); | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual InternalDbFunctionBuilder TranslateWith([NotNull] Func<IReadOnlyCollection<Expression>, IDbFunction, SqlFunctionExpression> translateCallback) | ||
{ | ||
_dbFunction.TranslateCallback = translateCallback; | ||
|
||
return this; | ||
} | ||
} | ||
} |
80 changes: 80 additions & 0 deletions
80
src/EFCore.Relational/Metadata/Internal/InternalDbFunctionParameterBuilder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// 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 JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Utilities; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata.Internal | ||
{ | ||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public class InternalDbFunctionParameterBuilder | ||
{ | ||
private readonly DbFunctionParameter _dbFunctionParameter; | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual DbFunctionParameter Parameter => _dbFunctionParameter; | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public InternalDbFunctionParameterBuilder([NotNull] DbFunctionParameter dbFunctionParameter) | ||
{ | ||
Check.NotNull(dbFunctionParameter, nameof(dbFunctionParameter)); | ||
|
||
_dbFunctionParameter = dbFunctionParameter; | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual InternalDbFunctionParameterBuilder HasName([NotNull]string name, ConfigurationSource configurationSource) | ||
{ | ||
if (configurationSource.Overrides(_dbFunctionParameter.GetNameConfigurationSource()) | ||
|| _dbFunctionParameter.Name == name) | ||
{ | ||
_dbFunctionParameter.SetName(name, configurationSource); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual InternalDbFunctionParameterBuilder HasType([NotNull] Type type, ConfigurationSource configurationSource) | ||
{ | ||
if (configurationSource.Overrides(_dbFunctionParameter.GetParameterTypeConfigurationSource()) | ||
|| _dbFunctionParameter.ParameterType == type) | ||
{ | ||
_dbFunctionParameter.SetParameterType(type, configurationSource); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public virtual InternalDbFunctionParameterBuilder HasIndex(int index, ConfigurationSource configurationSource) | ||
{ | ||
if (configurationSource.Overrides(_dbFunctionParameter.GetParameterIndexConfigurationSource()) | ||
|| _dbFunctionParameter.Index == index) | ||
{ | ||
_dbFunctionParameter.SetParameterIndex(index, configurationSource); | ||
} | ||
|
||
return this; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
src/EFCore.Relational/Query/ExpressionTranslators/ICompositeMethodCallTranslator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// 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.Linq.Expressions; | ||
using JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Metadata; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Query.ExpressionTranslators | ||
{ | ||
/// <summary> | ||
/// A LINQ expression translator for CLR <see cref="MethodCallExpression" /> expressions. | ||
/// </summary> | ||
public interface ICompositeMethodCallTranslator | ||
{ | ||
/// <summary> | ||
/// Translates the given method call expression. | ||
/// </summary> | ||
/// <param name="methodCallExpression"> The method call expression. </param> | ||
/// <param name="model"> The current model. </param> | ||
/// <returns> | ||
/// A SQL expression representing the translated MethodCallExpression. | ||
/// </returns> | ||
Expression Translate([NotNull] MethodCallExpression methodCallExpression, [NotNull] IModel model); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
src/EFCore.Relational/Query/Internal/RelationalEvaluatableExpressionFilter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// 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.Linq.Expressions; | ||
using JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Metadata; | ||
using Microsoft.EntityFrameworkCore.Utilities; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Query.Internal | ||
{ | ||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public class RelationalEvaluatableExpressionFilter : EvaluatableExpressionFilter | ||
{ | ||
private readonly IModel _model; | ||
|
||
public RelationalEvaluatableExpressionFilter([NotNull] IModel model) | ||
{ | ||
Check.NotNull(model, nameof(model)); | ||
|
||
_model = model; | ||
} | ||
|
||
public override bool IsEvaluatableMethodCall(MethodCallExpression methodCallExpression) | ||
=> _model.Relational().FindDbFunction(methodCallExpression.Method) == null | ||
&& base.IsEvaluatableMethodCall(methodCallExpression); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
src/EFCore/Metadata/Conventions/Internal/IModelAnnotationChangedConvention.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// 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 JetBrains.Annotations; | ||
using Microsoft.EntityFrameworkCore.Infrastructure; | ||
using Microsoft.EntityFrameworkCore.Metadata.Internal; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal | ||
{ | ||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
public interface IModelAnnotationChangedConvention | ||
{ | ||
/// <summary> | ||
/// This API supports the Entity Framework Core infrastructure and is not intended to be used | ||
/// directly from your code. This API may change or be removed in future releases. | ||
/// </summary> | ||
Annotation Apply( | ||
[NotNull] InternalModelBuilder modelBuilder, | ||
[NotNull] string name, | ||
[CanBeNull] Annotation annotation, | ||
[CanBeNull] Annotation oldAnnotation); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be singleton?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No.
The IEvaluatableExpressionFilter needs access to the current model in order to know which methods are marked as translatable. The ParameterExtractingExpressionVisitor will try to evaluate methods at query compilation not marked as translatable which also have constant parameters.
We could look at injecting the model directly into the ParameterExtractingExpressionVisitor, but that will involve making it a scoped service and make the code there more confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anpete - I'm confused on your thumbs up. Are you for leaving the code as is, or looking into if it can be moved into ParameterExtractingExpressionVisitor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leave as is