Skip to content

Commit 6efe5ab

Browse files
committed
SQL Server: window functions (SUM, AVG, MAX, MIN)
1 parent cdd9587 commit 6efe5ab

File tree

39 files changed

+4359
-537
lines changed

39 files changed

+4359
-537
lines changed

samples/Thinktecture.EntityFrameworkCore.SqlServer.Samples/SamplesContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public IServiceProvider CreateServiceProvider(string? schema = null)
4848
if (schema != null)
4949
sqlOptions.MigrationsHistoryTable("__EFMigrationsHistory", schema);
5050

51-
sqlOptions.AddRowNumberSupport()
51+
sqlOptions.AddWindowFunctionsSupport()
5252
.AddTenantDatabaseSupport<DemoTenantDatabaseProviderFactory>()
5353
.AddBulkOperationSupport()
5454
.AddCollectionParameterSupport()

samples/Thinktecture.EntityFrameworkCore.Sqlite.Samples/SamplesContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public IServiceProvider CreateServiceProvider()
4545
.UseSqlite(ConnectionString, sqlOptions =>
4646
{
4747
sqlOptions.AddBulkOperationSupport()
48-
.AddRowNumberSupport();
48+
.AddWindowFunctionsSupport();
4949
})
5050
.EnableSensitiveDataLogging()
5151
.UseLoggerFactory(_loggerFactory)

src/Thinktecture.EntityFrameworkCore.Relational/EntityFrameworkCore/Infrastructure/RelationalDbContextOptionsExtension.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ public IRelationalDbContextComponentDecorator ComponentDecorator
5555
public bool AddNestedTransactionsSupport { get; set; }
5656

5757
/// <summary>
58-
/// Enables and disables support for "RowNumber".
58+
/// Enables and disables support for windows functions like "RowNumber".
5959
/// </summary>
60-
public bool AddRowNumberSupport { get; set; }
60+
public bool AddWindowFunctionsSupport { get; set; }
6161

6262
/// <summary>
6363
/// Enables and disables support for 'tenant database support'.
@@ -253,8 +253,8 @@ private string CreateLogFragment()
253253
if (_extension.AddNestedTransactionsSupport)
254254
sb.Append("NestedTransactionsSupport ");
255255

256-
if (_extension.AddRowNumberSupport)
257-
sb.Append("RowNumberSupport ");
256+
if (_extension.AddWindowFunctionsSupport)
257+
sb.Append("WindowFunctionsSupport ");
258258

259259
if (_extension.AddTenantDatabaseSupport)
260260
sb.Append("TenantDatabaseSupport ");
@@ -278,7 +278,7 @@ public override int GetServiceProviderHashCode()
278278
hashCode.Add(_extension.AddSchemaRespectingComponents);
279279
hashCode.Add(_extension.AddNestedTransactionsSupport);
280280
hashCode.Add(_extension.AddTenantDatabaseSupport);
281-
hashCode.Add(_extension.AddRowNumberSupport);
281+
hashCode.Add(_extension.AddWindowFunctionsSupport);
282282
hashCode.Add(_extension.ComponentDecorator);
283283
hashCode.Add(_extension._stringBuilderPolicy.InitialCapacity);
284284
hashCode.Add(_extension._stringBuilderPolicy.MaximumRetainedCapacity);
@@ -302,7 +302,7 @@ public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo
302302
&& _extension.AddSchemaRespectingComponents == otherRelationalInfo._extension.AddSchemaRespectingComponents
303303
&& _extension.AddNestedTransactionsSupport == otherRelationalInfo._extension.AddNestedTransactionsSupport
304304
&& _extension.AddTenantDatabaseSupport == otherRelationalInfo._extension.AddTenantDatabaseSupport
305-
&& _extension.AddRowNumberSupport == otherRelationalInfo._extension.AddRowNumberSupport
305+
&& _extension.AddWindowFunctionsSupport == otherRelationalInfo._extension.AddWindowFunctionsSupport
306306
&& _extension._stringBuilderPolicy.InitialCapacity == otherRelationalInfo._extension._stringBuilderPolicy.InitialCapacity
307307
&& _extension._stringBuilderPolicy.MaximumRetainedCapacity == otherRelationalInfo._extension._stringBuilderPolicy.MaximumRetainedCapacity
308308
&& _extension.ComponentDecorator.Equals(otherRelationalInfo._extension.ComponentDecorator);
@@ -364,7 +364,7 @@ public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
364364
debugInfo["Thinktecture:CustomRelationalQueryContextFactory"] = _extension.UseThinktectureRelationalQueryContextFactory.ToString(CultureInfo.InvariantCulture);
365365
debugInfo["Thinktecture:SchemaRespectingComponents"] = _extension.AddSchemaRespectingComponents.ToString(CultureInfo.InvariantCulture);
366366
debugInfo["Thinktecture:NestedTransactionsSupport"] = _extension.AddNestedTransactionsSupport.ToString(CultureInfo.InvariantCulture);
367-
debugInfo["Thinktecture:RowNumberSupport"] = _extension.AddRowNumberSupport.ToString(CultureInfo.InvariantCulture);
367+
debugInfo["Thinktecture:WindowFunctionsSupport"] = _extension.AddWindowFunctionsSupport.ToString(CultureInfo.InvariantCulture);
368368
debugInfo["Thinktecture:TenantDatabaseSupport"] = _extension.AddTenantDatabaseSupport.ToString(CultureInfo.InvariantCulture);
369369
debugInfo["Thinktecture:EvaluatableExpressionFilterPlugins"] = String.Join(", ", _extension._evaluatableExpressionFilterPlugins.Select(t => t.ShortDisplayName()));
370370
debugInfo["Thinktecture:ServiceDescriptors"] = String.Join(", ", _extension._serviceDescriptors);

src/Thinktecture.EntityFrameworkCore.Relational/EntityFrameworkCore/Infrastructure/RelationalDbContextOptionsExtensionOptions.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ namespace Thinktecture.EntityFrameworkCore.Infrastructure;
99
public class RelationalDbContextOptionsExtensionOptions : ISingletonOptions
1010
{
1111
/// <summary>
12-
/// Indication whether the support for "RowNumber" is enabled or not.
12+
/// Indication whether the support for windows functions is enabled or not.
1313
/// </summary>
14-
public bool RowNumberSupportEnabled { get; private set; }
14+
public bool WindowFunctionsSupportEnabled { get; private set; }
1515

1616
/// <summary>
1717
/// Indication whether the 'tenant database support' is enabled or not.
@@ -23,7 +23,7 @@ public void Initialize(IDbContextOptions options)
2323
{
2424
var extension = GetExtension(options);
2525

26-
RowNumberSupportEnabled = extension.AddRowNumberSupport;
26+
WindowFunctionsSupportEnabled = extension.AddWindowFunctionsSupport;
2727
TenantDatabaseSupportEnabled = extension.AddTenantDatabaseSupport;
2828
}
2929

@@ -32,8 +32,8 @@ public void Validate(IDbContextOptions options)
3232
{
3333
var extension = GetExtension(options);
3434

35-
if (extension.AddRowNumberSupport != RowNumberSupportEnabled)
36-
throw new InvalidOperationException($"The setting '{nameof(RelationalDbContextOptionsExtension.AddRowNumberSupport)}' has been changed.");
35+
if (extension.AddWindowFunctionsSupport != WindowFunctionsSupportEnabled)
36+
throw new InvalidOperationException($"The setting '{nameof(RelationalDbContextOptionsExtension.AddWindowFunctionsSupport)}' has been changed.");
3737

3838
if (extension.AddTenantDatabaseSupport != TenantDatabaseSupportEnabled)
3939
throw new InvalidOperationException($"The setting '{nameof(RelationalDbContextOptionsExtension.AddTenantDatabaseSupport)}' has been changed.");
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,67 @@
1-
using System.Reflection;
2-
using Microsoft.EntityFrameworkCore.Diagnostics;
3-
using Microsoft.EntityFrameworkCore.Query;
4-
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
5-
using Microsoft.EntityFrameworkCore.Storage;
6-
using Thinktecture.EntityFrameworkCore.Query.SqlExpressions;
7-
8-
namespace Thinktecture.EntityFrameworkCore.Query.ExpressionTranslators;
9-
10-
/// <summary>
11-
/// Translated extension method "RowNumber"
12-
/// </summary>
13-
public sealed class RowNumberTranslator : IMethodCallTranslator
14-
{
15-
private readonly ISqlExpressionFactory _sqlExpressionFactory;
16-
17-
internal RowNumberTranslator(ISqlExpressionFactory sqlExpressionFactory)
18-
{
19-
_sqlExpressionFactory = sqlExpressionFactory;
20-
}
21-
22-
/// <inheritdoc />
23-
public SqlExpression? Translate(
24-
SqlExpression? instance,
25-
MethodInfo method,
26-
IReadOnlyList<SqlExpression> arguments,
27-
IDiagnosticsLogger<DbLoggerCategory.Query> logger)
28-
{
29-
ArgumentNullException.ThrowIfNull(method);
30-
ArgumentNullException.ThrowIfNull(arguments);
31-
32-
if (method.DeclaringType != typeof(RelationalDbFunctionsExtensions))
33-
return null;
34-
35-
switch (method.Name)
36-
{
37-
case nameof(RelationalDbFunctionsExtensions.OrderBy):
38-
{
39-
var orderBy = arguments.Skip(1).Select(e => new OrderingExpression(_sqlExpressionFactory.ApplyDefaultTypeMapping(e), true)).ToList();
40-
return new RowNumberClauseOrderingsExpression(orderBy);
41-
}
42-
case nameof(RelationalDbFunctionsExtensions.OrderByDescending):
43-
{
44-
var orderBy = arguments.Skip(1).Select(e => new OrderingExpression(_sqlExpressionFactory.ApplyDefaultTypeMapping(e), false)).ToList();
45-
return new RowNumberClauseOrderingsExpression(orderBy);
46-
}
47-
case nameof(RelationalDbFunctionsExtensions.ThenBy):
48-
{
49-
var orderBy = arguments.Skip(1).Select(e => new OrderingExpression(_sqlExpressionFactory.ApplyDefaultTypeMapping(e), true));
50-
return ((RowNumberClauseOrderingsExpression)arguments[0]).AddColumns(orderBy);
51-
}
52-
case nameof(RelationalDbFunctionsExtensions.ThenByDescending):
53-
{
54-
var orderBy = arguments.Skip(1).Select(e => new OrderingExpression(_sqlExpressionFactory.ApplyDefaultTypeMapping(e), false));
55-
return ((RowNumberClauseOrderingsExpression)arguments[0]).AddColumns(orderBy);
56-
}
57-
case nameof(RelationalDbFunctionsExtensions.RowNumber):
58-
{
59-
var partitionBy = arguments.Skip(1).Take(arguments.Count - 2).Select(e => _sqlExpressionFactory.ApplyDefaultTypeMapping(e)).ToList();
60-
var orderings = (RowNumberClauseOrderingsExpression)arguments[^1];
61-
return new RowNumberExpression(partitionBy, orderings.Orderings, RelationalTypeMapping.NullMapping);
62-
}
63-
default:
64-
throw new InvalidOperationException($"Unexpected method '{method.Name}' in '{nameof(RelationalDbFunctionsExtensions)}'.");
65-
}
66-
}
67-
}
1+
using System.Reflection;
2+
using Microsoft.EntityFrameworkCore.Diagnostics;
3+
using Microsoft.EntityFrameworkCore.Query;
4+
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
5+
using Microsoft.EntityFrameworkCore.Storage;
6+
using Thinktecture.EntityFrameworkCore.Query.SqlExpressions;
7+
8+
namespace Thinktecture.EntityFrameworkCore.Query.ExpressionTranslators;
9+
10+
/// <summary>
11+
/// Translates extension methods like "RowNumber"
12+
/// </summary>
13+
public sealed class RelationalDbFunctionsTranslator : IMethodCallTranslator
14+
{
15+
private readonly ISqlExpressionFactory _sqlExpressionFactory;
16+
17+
internal RelationalDbFunctionsTranslator(ISqlExpressionFactory sqlExpressionFactory)
18+
{
19+
_sqlExpressionFactory = sqlExpressionFactory;
20+
}
21+
22+
/// <inheritdoc />
23+
public SqlExpression? Translate(
24+
SqlExpression? instance,
25+
MethodInfo method,
26+
IReadOnlyList<SqlExpression> arguments,
27+
IDiagnosticsLogger<DbLoggerCategory.Query> logger)
28+
{
29+
ArgumentNullException.ThrowIfNull(method);
30+
ArgumentNullException.ThrowIfNull(arguments);
31+
32+
if (method.DeclaringType != typeof(RelationalDbFunctionsExtensions))
33+
return null;
34+
35+
switch (method.Name)
36+
{
37+
case nameof(RelationalDbFunctionsExtensions.OrderBy):
38+
{
39+
var orderBy = arguments.Skip(1).Select(e => new OrderingExpression(_sqlExpressionFactory.ApplyDefaultTypeMapping(e), true)).ToList();
40+
return new WindowFunctionOrderingsExpression(orderBy);
41+
}
42+
case nameof(RelationalDbFunctionsExtensions.OrderByDescending):
43+
{
44+
var orderBy = arguments.Skip(1).Select(e => new OrderingExpression(_sqlExpressionFactory.ApplyDefaultTypeMapping(e), false)).ToList();
45+
return new WindowFunctionOrderingsExpression(orderBy);
46+
}
47+
case nameof(RelationalDbFunctionsExtensions.ThenBy):
48+
{
49+
var orderBy = arguments.Skip(1).Select(e => new OrderingExpression(_sqlExpressionFactory.ApplyDefaultTypeMapping(e), true));
50+
return ((WindowFunctionOrderingsExpression)arguments[0]).AddColumns(orderBy);
51+
}
52+
case nameof(RelationalDbFunctionsExtensions.ThenByDescending):
53+
{
54+
var orderBy = arguments.Skip(1).Select(e => new OrderingExpression(_sqlExpressionFactory.ApplyDefaultTypeMapping(e), false));
55+
return ((WindowFunctionOrderingsExpression)arguments[0]).AddColumns(orderBy);
56+
}
57+
case nameof(RelationalDbFunctionsExtensions.RowNumber):
58+
{
59+
var partitionBy = arguments.Skip(1).Take(arguments.Count - 2).Select(e => _sqlExpressionFactory.ApplyDefaultTypeMapping(e)).ToList();
60+
var orderings = (WindowFunctionOrderingsExpression)arguments[^1];
61+
return new RowNumberExpression(partitionBy, orderings.Orderings, RelationalTypeMapping.NullMapping);
62+
}
63+
default:
64+
throw new InvalidOperationException($"Unexpected method '{method.Name}' in '{nameof(RelationalDbFunctionsExtensions)}'.");
65+
}
66+
}
67+
}

src/Thinktecture.EntityFrameworkCore.Relational/EntityFrameworkCore/Query/ExpressionTranslators/RelationalMethodCallTranslatorPlugin.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ public RelationalMethodCallTranslatorPlugin(RelationalDbContextOptionsExtensionO
2020

2121
var translators = new List<IMethodCallTranslator>();
2222

23-
if (options.RowNumberSupportEnabled)
24-
translators.Add(new RowNumberTranslator(sqlExpressionFactory));
23+
if (options.WindowFunctionsSupportEnabled)
24+
translators.Add(new RelationalDbFunctionsTranslator(sqlExpressionFactory));
2525

2626
Translators = translators;
2727
}

0 commit comments

Comments
 (0)