Skip to content

Commit ec6c702

Browse files
authored
Add Std Dev and Variance using EF.Functions (#269)
* Add Std Dev and Variance using EF.Functions
1 parent 98bdd0a commit ec6c702

File tree

8 files changed

+928
-385
lines changed

8 files changed

+928
-385
lines changed

src/EFCore.Jet/Extensions/JetDbFunctionsExtensions.cs

Lines changed: 334 additions & 35 deletions
Large diffs are not rendered by default.

src/EFCore.Jet/Extensions/JetServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public static IServiceCollection AddEntityFrameworkJet([NotNull] this IServiceCo
5959
.TryAdd<ISingletonOptions, IJetOptions>(p => p.GetRequiredService<IJetOptions>())
6060
.TryAdd<IQueryCompilationContextFactory, JetQueryCompilationContextFactory>()
6161
.TryAdd<IMethodCallTranslatorProvider, JetMethodCallTranslatorProvider>()
62+
.TryAdd<IAggregateMethodCallTranslatorProvider, JetAggregateMethodCallTranslatorProvider>()
6263
.TryAdd<IMemberTranslatorProvider, JetMemberTranslatorProvider>()
6364
.TryAdd<IQuerySqlGeneratorFactory, JetQuerySqlGeneratorFactory>()
6465
.TryAdd<IRelationalSqlTranslatingExpressionVisitorFactory, JetSqlTranslatingExpressionVisitorFactory>()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Microsoft.EntityFrameworkCore.Query;
2+
3+
namespace EntityFrameworkCore.Jet.Query.ExpressionTranslators.Internal;
4+
5+
/// <summary>
6+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
7+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
8+
/// any release. You should only use it directly in your code with extreme caution and knowing that
9+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
10+
/// </summary>
11+
public class JetAggregateMethodCallTranslatorProvider : RelationalAggregateMethodCallTranslatorProvider
12+
{
13+
/// <summary>
14+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
15+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
16+
/// any release. You should only use it directly in your code with extreme caution and knowing that
17+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
18+
/// </summary>
19+
public JetAggregateMethodCallTranslatorProvider(RelationalAggregateMethodCallTranslatorProviderDependencies dependencies)
20+
: base(dependencies)
21+
{
22+
var sqlExpressionFactory = dependencies.SqlExpressionFactory;
23+
var typeMappingSource = dependencies.RelationalTypeMappingSource;
24+
25+
AddTranslators(
26+
[
27+
new JetStatisticsAggregateMethodTranslator(sqlExpressionFactory, typeMappingSource)
28+
]);
29+
}
30+
}

src/EFCore.Jet/Query/ExpressionTranslators/Internal/JetMethodCallTranslatorProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class JetMethodCallTranslatorProvider : RelationalMethodCallTranslatorPro
1616
/// directly from your code. This API may change or be removed in future releases.
1717
/// </summary>
1818
public JetMethodCallTranslatorProvider(
19-
[NotNull] RelationalMethodCallTranslatorProviderDependencies dependencies)
19+
RelationalMethodCallTranslatorProviderDependencies dependencies)
2020
: base(dependencies)
2121
{
2222
var sqlExpressionFactory = (JetSqlExpressionFactory)dependencies.SqlExpressionFactory;
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using System.Collections.Generic;
2+
using System.Reflection;
3+
using Microsoft.EntityFrameworkCore;
4+
using Microsoft.EntityFrameworkCore.Diagnostics;
5+
using Microsoft.EntityFrameworkCore.Query;
6+
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
7+
using Microsoft.EntityFrameworkCore.Storage;
8+
9+
namespace EntityFrameworkCore.Jet.Query.ExpressionTranslators.Internal;
10+
11+
/// <summary>
12+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
13+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
14+
/// any release. You should only use it directly in your code with extreme caution and knowing that
15+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
16+
/// </summary>
17+
public class JetStatisticsAggregateMethodTranslator : IAggregateMethodCallTranslator
18+
{
19+
private readonly ISqlExpressionFactory _sqlExpressionFactory;
20+
private readonly RelationalTypeMapping _doubleTypeMapping;
21+
22+
/// <summary>
23+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
24+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
25+
/// any release. You should only use it directly in your code with extreme caution and knowing that
26+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
27+
/// </summary>
28+
public JetStatisticsAggregateMethodTranslator(
29+
ISqlExpressionFactory sqlExpressionFactory,
30+
IRelationalTypeMappingSource typeMappingSource)
31+
{
32+
_sqlExpressionFactory = sqlExpressionFactory;
33+
_doubleTypeMapping = typeMappingSource.FindMapping(typeof(double))!;
34+
}
35+
36+
/// <summary>
37+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
38+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
39+
/// any release. You should only use it directly in your code with extreme caution and knowing that
40+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
41+
/// </summary>
42+
public virtual SqlExpression? Translate(
43+
MethodInfo method,
44+
EnumerableExpression source,
45+
IReadOnlyList<SqlExpression> arguments,
46+
IDiagnosticsLogger<DbLoggerCategory.Query> logger)
47+
{
48+
// Docs: https://docs.microsoft.com/sql/t-sql/functions/aggregate-functions-transact-sql
49+
50+
if (method.DeclaringType != typeof(JetDbFunctionsExtensions)
51+
|| source.Selector is not SqlExpression sqlExpression)
52+
{
53+
return null;
54+
}
55+
56+
var functionName = method.Name switch
57+
{
58+
nameof(JetDbFunctionsExtensions.StandardDeviationSample) => "StDev",
59+
nameof(JetDbFunctionsExtensions.StandardDeviationPopulation) => "StDevP",
60+
nameof(JetDbFunctionsExtensions.VarianceSample) => "Var",
61+
nameof(JetDbFunctionsExtensions.VariancePopulation) => "VarP",
62+
_ => null
63+
};
64+
65+
if (functionName is null)
66+
{
67+
return null;
68+
}
69+
70+
return _sqlExpressionFactory.Function(functionName, [sqlExpression], nullable: true, argumentsPropagateNullability: [false], typeof(double), _doubleTypeMapping);
71+
}
72+
}

test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_odbc_x86.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13060,6 +13060,8 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Sel
1306013060
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Select_mathf_truncate(async: True)
1306113061
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Select_ToString_IndexOf(async: False)
1306213062
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Select_ToString_IndexOf(async: True)
13063+
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.StandardDeviation(async: False)
13064+
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.StandardDeviation(async: True)
1306313065
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Static_equals_int_compared_to_long(isAsync: False)
1306413066
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Static_equals_int_compared_to_long(isAsync: True)
1306513067
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Static_equals_nullable_datetime_compared_to_non_nullable(isAsync: False)
@@ -13194,6 +13196,8 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Tri
1319413196
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.TrimEnd_without_arguments_in_predicate(isAsync: True)
1319513197
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.TrimStart_without_arguments_in_predicate(isAsync: False)
1319613198
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.TrimStart_without_arguments_in_predicate(isAsync: True)
13199+
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Variance(async: False)
13200+
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Variance(async: True)
1319713201
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_DateOnly_FromDateTime(async: False)
1319813202
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_DateOnly_FromDateTime(async: True)
1319913203
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_functions_nested(isAsync: False)

test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_oledb_x86.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14350,6 +14350,8 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Sel
1435014350
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Select_mathf_truncate(async: True)
1435114351
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Select_ToString_IndexOf(async: False)
1435214352
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Select_ToString_IndexOf(async: True)
14353+
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.StandardDeviation(async: False)
14354+
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.StandardDeviation(async: True)
1435314355
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Static_equals_int_compared_to_long(isAsync: False)
1435414356
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Static_equals_int_compared_to_long(isAsync: True)
1435514357
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Static_equals_nullable_datetime_compared_to_non_nullable(isAsync: False)
@@ -14484,6 +14486,8 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Tri
1448414486
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.TrimEnd_without_arguments_in_predicate(isAsync: True)
1448514487
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.TrimStart_without_arguments_in_predicate(isAsync: False)
1448614488
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.TrimStart_without_arguments_in_predicate(isAsync: True)
14489+
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Variance(async: False)
14490+
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Variance(async: True)
1448714491
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_DateOnly_FromDateTime(async: False)
1448814492
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_DateOnly_FromDateTime(async: True)
1448914493
EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindFunctionsQueryJetTest.Where_functions_nested(isAsync: False)

0 commit comments

Comments
 (0)