Skip to content

Commit 33bf654

Browse files
committed
Adjusted code due to breaking change in EF 9
1 parent 6388d3f commit 33bf654

File tree

28 files changed

+268
-238
lines changed

28 files changed

+268
-238
lines changed

.github/workflows/main.yml

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,41 @@
1-
name: CI
2-
3-
on:
4-
push
5-
6-
env:
7-
UseSqlServerContainer: true
8-
9-
jobs:
10-
build:
11-
runs-on: ubuntu-latest
12-
13-
steps:
14-
15-
- name: install .NET Core 8 SDK
16-
uses: actions/setup-dotnet@v2
17-
with:
18-
dotnet-version: 8.0.x
19-
include-prerelease: false
20-
21-
- name: checkout repository
22-
uses: actions/checkout@v2
23-
24-
- name: dotnet restore
25-
run: dotnet restore
26-
27-
- name: build
28-
run: dotnet build --configuration Release --no-restore
29-
30-
- name: test
31-
run: dotnet test --configuration Release --no-build
32-
33-
- name: test results
34-
uses: EnricoMi/publish-unit-test-result-action@v2
35-
id: test-results
36-
if: always()
37-
with:
38-
check_name: tests results
39-
trx_files: "**/test-results/**/*.trx"
1+
name: CI
2+
3+
on:
4+
push
5+
6+
env:
7+
UseSqlServerContainer: true
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
15+
- name: install .NET Core 8/9 SDKs
16+
uses: actions/setup-dotnet@v2
17+
with:
18+
include-prerelease: false
19+
dotnet-version: |
20+
8.0.x
21+
9.0.x
22+
23+
- name: checkout repository
24+
uses: actions/checkout@v2
25+
26+
- name: dotnet restore
27+
run: dotnet restore
28+
29+
- name: build
30+
run: dotnet build --configuration Release --no-restore
31+
32+
- name: test
33+
run: dotnet test --configuration Release --no-build
34+
35+
- name: test results
36+
uses: EnricoMi/publish-unit-test-result-action@v2
37+
id: test-results
38+
if: always()
39+
with:
40+
check_name: tests results
41+
trx_files: "**/test-results/**/*.trx"

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<Copyright>(c) $([System.DateTime]::Now.Year), Pawel Gerr. All rights reserved.</Copyright>
5-
<VersionPrefix>8.1.1</VersionPrefix>
5+
<VersionPrefix>9.0.0</VersionPrefix>
66
<Authors>Pawel Gerr</Authors>
77
<GenerateDocumentationFile>true</GenerateDocumentationFile>
88
<PackageProjectUrl>https://dev.azure.com/pawelgerr/Thinktecture.EntityFrameworkCore</PackageProjectUrl>
@@ -13,7 +13,7 @@
1313
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
1414
<RootNamespace>Thinktecture</RootNamespace>
1515
<TargetFramework>net8.0</TargetFramework>
16-
<LangVersion>12.0</LangVersion>
16+
<LangVersion>13.0</LangVersion>
1717
<Nullable>enable</Nullable>
1818
<NoWarn>$(NoWarn);CA1303;MSB3884;</NoWarn>
1919
<ImplicitUsings>enable</ImplicitUsings>

Directory.Packages.props

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
<ItemGroup>
33
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
44
<PackageVersion Include="FluentAssertions" Version="6.12.2" />
5-
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10" />
6-
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.10" />
7-
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.10" />
8-
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.10" />
9-
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
10-
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="8.0.1" />
11-
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
12-
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="8.0.10" />
5+
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0" />
6+
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.0" />
7+
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0" />
8+
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
9+
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.0" />
10+
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
11+
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.0" />
12+
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="9.0.0" />
1313
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
1414
<PackageVersion Include="Microsoft.SourceLink.AzureRepos.Git" Version="8.0.0" PrivateAssets="all" />
1515
<PackageVersion Include="NSubstitute" Version="5.3.0" />

azure-pipelines.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ steps:
2323
includePreviewVersions: false
2424
installationPath: $(Agent.ToolsDirectory)/dotnet
2525

26+
- task: UseDotNet@2
27+
displayName: 'use .NET 9.0 SDK'
28+
inputs:
29+
packageType: sdk
30+
version: 9.0.x
31+
includePreviewVersions: false
32+
installationPath: $(Agent.ToolsDirectory)/dotnet
33+
2634
- script: |
2735
echo dotnet --version
2836
dotnet --version

src/Thinktecture.EntityFrameworkCore.Relational/EntityFrameworkCore/Query/SqlExpressions/WindowFunctionOrderingsExpression.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Linq.Expressions;
2+
using System.Reflection;
23
using Microsoft.EntityFrameworkCore.Query;
34
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
45
using Microsoft.EntityFrameworkCore.Storage;
@@ -10,6 +11,8 @@ namespace Thinktecture.EntityFrameworkCore.Query.SqlExpressions;
1011
/// </summary>
1112
public sealed class WindowFunctionOrderingsExpression : SqlExpression, INotNullableSqlExpression
1213
{
14+
private static readonly ConstructorInfo _quotingConstructor = typeof(WindowFunctionOrderingsExpression).GetConstructors().Single();
15+
1316
/// <summary>
1417
/// Orderings.
1518
/// </summary>
@@ -39,6 +42,13 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
3942
return ReferenceEquals(visited, Orderings) ? this : new WindowFunctionOrderingsExpression(visited);
4043
}
4144

45+
/// <inheritdoc />
46+
public override Expression Quote()
47+
{
48+
return New(_quotingConstructor,
49+
NewArrayInit(typeof(OrderingExpression), initializers: Orderings.Select(o => o.Quote())));
50+
}
51+
4252
/// <inheritdoc />
4353
protected override void Print(ExpressionPrinter expressionPrinter)
4454
{

src/Thinktecture.EntityFrameworkCore.Relational/EntityFrameworkCore/Query/SqlExpressions/WindowFunctionPartitionByExpression.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Linq.Expressions;
2+
using System.Reflection;
23
using Microsoft.EntityFrameworkCore.Query;
34
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
45
using Microsoft.EntityFrameworkCore.Storage;
@@ -10,6 +11,8 @@ namespace Thinktecture.EntityFrameworkCore.Query.SqlExpressions;
1011
/// </summary>
1112
public class WindowFunctionPartitionByExpression : SqlExpression, INotNullableSqlExpression
1213
{
14+
private static readonly ConstructorInfo _quotingConstructor = typeof(WindowFunctionPartitionByExpression).GetConstructors().Single();
15+
1316
/// <summary>
1417
/// Partition by expressions.
1518
/// </summary>
@@ -39,6 +42,13 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
3942
return ReferenceEquals(visited, PartitionBy) ? this : new WindowFunctionPartitionByExpression(visited);
4043
}
4144

45+
/// <inheritdoc />
46+
public override Expression Quote()
47+
{
48+
return New(_quotingConstructor,
49+
NewArrayInit(typeof(SqlExpression), initializers: PartitionBy.Select(o => o.Quote())));
50+
}
51+
4252
/// <inheritdoc />
4353
protected override void Print(ExpressionPrinter expressionPrinter)
4454
{

src/Thinktecture.EntityFrameworkCore.Relational/EntityFrameworkCore/Query/ThinktectureSqlNullabilityProcessor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ public class ThinktectureSqlNullabilityProcessor : SqlNullabilityProcessor
1212
/// <inheritdoc />
1313
public ThinktectureSqlNullabilityProcessor(
1414
RelationalParameterBasedSqlProcessorDependencies dependencies,
15-
bool useRelationalNulls)
16-
: base(dependencies, useRelationalNulls)
15+
RelationalParameterBasedSqlProcessorParameters parameters)
16+
: base(dependencies, parameters)
1717
{
1818
}
1919

src/Thinktecture.EntityFrameworkCore.Relational/Extensions/RelationalQueryableMethodTranslatingExpressionVisitorExtensions.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.EntityFrameworkCore.Infrastructure;
44
using Microsoft.EntityFrameworkCore.Query;
55
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
6+
using Thinktecture.EntityFrameworkCore;
67
using Thinktecture.EntityFrameworkCore.Internal;
78
using Thinktecture.Internal;
89

@@ -54,8 +55,13 @@ private static Expression TranslateTableHints(
5455
ShapedQueryExpression shapedQueryExpression,
5556
MethodCallExpression methodCallExpression)
5657
{
57-
var tableHintsExpression = (TableHintsExpression)methodCallExpression.Arguments[1] ?? throw new InvalidOperationException("Table hints cannot be null.");
58-
var tableHints = tableHintsExpression.Value ?? throw new Exception("No table hints provided.");
58+
var hintArgs = methodCallExpression.Arguments[1];
59+
var tableHints = hintArgs switch
60+
{
61+
TableHintsExpression tableHintsExpression => tableHintsExpression.Value,
62+
ConstantExpression constantExpression => (IReadOnlyList<ITableHint>?)constantExpression.Value ?? throw new Exception("No table hints provided."),
63+
_ => throw new NotSupportedException($"Table hint argument of type '{hintArgs.GetType().FullName}' is not supported.")
64+
};
5965

6066
if (tableHints.Count == 0)
6167
return shapedQueryExpression;

src/Thinktecture.EntityFrameworkCore.SqlServer.Testing/EntityFrameworkCore/Testing/SqlServerTestDbContextProvider.cs

Lines changed: 2 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -239,76 +239,6 @@ protected virtual IDbContextTransaction BeginTransaction(T ctx)
239239
return ctx.Database.BeginTransaction(_sharedTablesIsolationLevel);
240240
}
241241

242-
/// <summary>
243-
/// Starts a new transaction for migration and cleanup.
244-
/// </summary>
245-
/// <param name="ctx">Database context.</param>
246-
/// <returns>An instance of <see cref="IDbContextTransaction"/>.</returns>
247-
protected virtual IDbContextTransaction? BeginMigrationAndCleanupTransaction(T ctx)
248-
{
249-
ArgumentNullException.ThrowIfNull(ctx);
250-
251-
if (!_lockTableEnabled)
252-
return ctx.Database.BeginTransaction(IsolationLevel.Serializable);
253-
254-
var sqlGenerationHelper = ctx.GetService<ISqlGenerationHelper>();
255-
var lockTableName = sqlGenerationHelper.DelimitIdentifier(_lockTableName, _lockTableSchema);
256-
257-
CreateTestIsolationTable(ctx, lockTableName);
258-
259-
for (var i = 0;; i++)
260-
{
261-
var tx = ctx.Database.BeginTransaction(IsolationLevel.Serializable);
262-
263-
try
264-
{
265-
LockDatabase(ctx, lockTableName);
266-
return tx;
267-
}
268-
catch (Exception)
269-
{
270-
tx.Dispose();
271-
272-
if (i > _maxNumberOfLockRetries)
273-
throw;
274-
275-
var delay = new TimeSpan(_random.NextInt64(_minRetryDelay.Ticks, _maxRetryDelay.Ticks));
276-
Task.Delay(delay).GetAwaiter().GetResult();
277-
}
278-
}
279-
}
280-
281-
private void CreateTestIsolationTable(T ctx, string lockTableName)
282-
{
283-
var createTableSql = $"""
284-
IF(OBJECT_ID('{lockTableName}') IS NULL)
285-
CREATE TABLE {lockTableName}(Id INT NOT NULL)
286-
""";
287-
288-
for (var i = 0;; i++)
289-
{
290-
try
291-
{
292-
ctx.Database.ExecuteSqlRaw(createTableSql);
293-
return;
294-
}
295-
catch (Exception)
296-
{
297-
if (i > _maxNumberOfLockRetries)
298-
throw;
299-
300-
var delay = new TimeSpan(_random.NextInt64(_minRetryDelay.Ticks, _maxRetryDelay.Ticks));
301-
Task.Delay(delay).GetAwaiter().GetResult();
302-
}
303-
}
304-
}
305-
306-
private static void LockDatabase(T ctx, string lockTableName)
307-
{
308-
var selectSql = $"SELECT * FROM {lockTableName} WITH (HOLDLOCK, UPDLOCK)";
309-
ctx.Database.ExecuteSqlRaw(selectSql);
310-
}
311-
312242
/// <summary>
313243
/// Runs migrations for provided <paramref name="ctx" />.
314244
/// </summary>
@@ -326,21 +256,7 @@ protected virtual void RunMigrations(T ctx)
326256
try
327257
{
328258
LogLevelSwitch.MinimumLogLevel = _testingLoggingOptions.MigrationLogLevel;
329-
330-
IDbContextTransaction? migrationTx = null;
331-
332-
if (ctx.Database.CurrentTransaction is null)
333-
migrationTx = BeginMigrationAndCleanupTransaction(ctx);
334-
335-
try
336-
{
337-
_migrationExecutionStrategy.Migrate(ctx);
338-
migrationTx?.Commit();
339-
}
340-
finally
341-
{
342-
migrationTx?.Dispose();
343-
}
259+
_migrationExecutionStrategy.Migrate(ctx);
344260
}
345261
finally
346262
{
@@ -427,22 +343,7 @@ private async Task DisposeContextsAndRollbackMigrationsAsync(CancellationToken c
427343
{
428344
// Create a new ctx as a last resort to rollback migrations and clean up the database
429345
await using var ctx = _actDbContext ?? _arrangeDbContext ?? _assertDbContext ?? CreateDbContext(_masterDbContextOptions, Schema is null ? null : new DbDefaultSchema(Schema));
430-
431-
IDbContextTransaction? migrationTx = null;
432-
433-
if (ctx.Database.CurrentTransaction is null)
434-
migrationTx = BeginMigrationAndCleanupTransaction(ctx);
435-
436-
try
437-
{
438-
await _isolationOptions.CleanupAsync(ctx, Schema, cancellationToken);
439-
440-
await (migrationTx?.CommitAsync(cancellationToken) ?? Task.CompletedTask);
441-
}
442-
finally
443-
{
444-
await (migrationTx?.DisposeAsync() ?? ValueTask.CompletedTask);
445-
}
346+
await _isolationOptions.CleanupAsync(ctx, Schema, cancellationToken);
446347
}
447348

448349
await (_arrangeDbContext?.DisposeAsync() ?? ValueTask.CompletedTask);

src/Thinktecture.EntityFrameworkCore.SqlServer/EntityFrameworkCore/Query/SqlExpressions/WindowFunctionExpression.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
using System.Diagnostics.CodeAnalysis;
12
using System.Linq.Expressions;
3+
using System.Reflection;
24
using Microsoft.EntityFrameworkCore.Query;
35
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
4-
using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
56
using Microsoft.EntityFrameworkCore.Storage;
67

78
namespace Thinktecture.EntityFrameworkCore.Query.SqlExpressions;
@@ -11,6 +12,8 @@ namespace Thinktecture.EntityFrameworkCore.Query.SqlExpressions;
1112
/// </summary>
1213
public class WindowFunctionExpression : SqlExpression
1314
{
15+
private static readonly ConstructorInfo _quotingConstructor = typeof(WindowFunctionExpression).GetConstructors().Single();
16+
1417
/// <summary>
1518
/// Creates a new instance of the <see cref="WindowFunctionExpression" /> class.
1619
/// </summary>
@@ -75,6 +78,20 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
7578
: this;
7679
}
7780

81+
/// <inheritdoc />
82+
[Experimental("EF9100")]
83+
public override Expression Quote()
84+
{
85+
return New(_quotingConstructor,
86+
Constant(Name),
87+
Constant(UseAsteriskWhenNoArguments),
88+
Constant(Type),
89+
RelationalExpressionQuotingUtilities.QuoteTypeMapping(TypeMapping),
90+
NewArrayInit(typeof(SqlExpression), Arguments.Select(a => a.Quote())),
91+
NewArrayInit(typeof(SqlExpression), Partitions.Select(p => p.Quote())),
92+
NewArrayInit(typeof(OrderingExpression), Orderings.Select(o => o.Quote())));
93+
}
94+
7895
/// <inheritdoc />
7996
protected override void Print(ExpressionPrinter expressionPrinter)
8097
{

0 commit comments

Comments
 (0)