Skip to content

Commit c282bb2

Browse files
Merge pull request #139 from TransactionProcessing/task/#63_database_simple_mode
Update DB migration to enforce SIMPLE recovery mode
2 parents 868d456 + 12c171b commit c282bb2

5 files changed

Lines changed: 107 additions & 14 deletions

File tree

TestHosts/TestHosts/Database/PataPawa/PataPawaContext.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using Microsoft.EntityFrameworkCore;
22
using Shared.General;
33
using System;
4+
using System.Threading;
5+
using System.Threading.Tasks;
46

57
namespace TestHosts.Database.PataPawa
68
{
@@ -59,5 +61,59 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) {
5961

6062
base.OnModelCreating(modelBuilder);
6163
}
64+
65+
private async Task SetDbInSimpleMode(CancellationToken cancellationToken)
66+
{
67+
var dbName = this.Database.GetDbConnection().Database;
68+
69+
var connection = this.Database.GetDbConnection();
70+
if (connection.State != System.Data.ConnectionState.Open)
71+
await connection.OpenAsync(cancellationToken);
72+
73+
// 1. Check current recovery model
74+
await using var checkCommand = connection.CreateCommand();
75+
checkCommand.CommandText = @"
76+
SELECT recovery_model_desc
77+
FROM sys.databases
78+
WHERE name = @dbName;
79+
";
80+
var param = checkCommand.CreateParameter();
81+
param.ParameterName = "@dbName";
82+
param.Value = dbName;
83+
checkCommand.Parameters.Add(param);
84+
85+
var result = await checkCommand.ExecuteScalarAsync(cancellationToken);
86+
var currentRecoveryModel = result?.ToString();
87+
88+
if (currentRecoveryModel != "SIMPLE")
89+
{
90+
// 2. Alter database outside transaction
91+
await using var alterCommand = connection.CreateCommand();
92+
alterCommand.CommandText = $@"
93+
ALTER DATABASE [{dbName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
94+
ALTER DATABASE [{dbName}] SET RECOVERY SIMPLE;
95+
ALTER DATABASE [{dbName}] SET MULTI_USER;
96+
";
97+
// Execute outside EF transaction
98+
await alterCommand.ExecuteNonQueryAsync(cancellationToken);
99+
}
100+
}
101+
102+
public virtual async Task MigrateAsync(CancellationToken cancellationToken)
103+
{
104+
if (this.Database.IsSqlServer())
105+
{
106+
try
107+
{
108+
await this.Database.MigrateAsync(cancellationToken);
109+
await this.SetDbInSimpleMode(cancellationToken);
110+
}
111+
catch (Exception ex)
112+
{
113+
// Log the exception or handle it as needed
114+
throw new InvalidOperationException("An error occurred while migrating the database.", ex);
115+
}
116+
}
117+
}
62118
}
63119
}

TestHosts/TestHosts/Database/TestBank/TestBankContext.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public virtual async Task MigrateAsync(CancellationToken cancellationToken)
7373
try
7474
{
7575
await this.Database.MigrateAsync(cancellationToken);
76+
await this.SetDbInSimpleMode(cancellationToken);
7677
}
7778
catch (Exception ex)
7879
{
@@ -81,5 +82,42 @@ public virtual async Task MigrateAsync(CancellationToken cancellationToken)
8182
}
8283
}
8384
}
85+
86+
private async Task SetDbInSimpleMode(CancellationToken cancellationToken)
87+
{
88+
var dbName = this.Database.GetDbConnection().Database;
89+
90+
var connection = this.Database.GetDbConnection();
91+
if (connection.State != System.Data.ConnectionState.Open)
92+
await connection.OpenAsync(cancellationToken);
93+
94+
// 1. Check current recovery model
95+
await using var checkCommand = connection.CreateCommand();
96+
checkCommand.CommandText = @"
97+
SELECT recovery_model_desc
98+
FROM sys.databases
99+
WHERE name = @dbName;
100+
";
101+
var param = checkCommand.CreateParameter();
102+
param.ParameterName = "@dbName";
103+
param.Value = dbName;
104+
checkCommand.Parameters.Add(param);
105+
106+
var result = await checkCommand.ExecuteScalarAsync(cancellationToken);
107+
var currentRecoveryModel = result?.ToString();
108+
109+
if (currentRecoveryModel != "SIMPLE")
110+
{
111+
// 2. Alter database outside transaction
112+
await using var alterCommand = connection.CreateCommand();
113+
alterCommand.CommandText = $@"
114+
ALTER DATABASE [{dbName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
115+
ALTER DATABASE [{dbName}] SET RECOVERY SIMPLE;
116+
ALTER DATABASE [{dbName}] SET MULTI_USER;
117+
";
118+
// Execute outside EF transaction
119+
await alterCommand.ExecuteNonQueryAsync(cancellationToken);
120+
}
121+
}
84122
}
85123
}

TestHosts/TestHosts/Program.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,7 @@
159159

160160
// Custom middleware
161161
app.UseMiddleware<TenantMiddleware>();
162-
app.AddRequestLogging();
163-
app.AddResponseLogging();
162+
app.AddRequestResponseLogging();
164163
app.AddExceptionHandler();
165164

166165
app.UseRouting();

TestHosts/TestHosts/Startup.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,15 @@ public async Task StartAsync(CancellationToken cancellationToken)
104104

105105
if (pataPawaContext.Database.IsRelational()) {
106106
// Example: apply migrations or seed data
107-
pataPawaContext.Database.Migrate();
107+
await pataPawaContext.Database.MigrateAsync(cancellationToken);
108108
}
109109
//else {
110110
// await pataPawaContext.Database.EnsureCreatedAsync(cancellationToken);
111111
//}
112112

113113
TestBankContext bankContext = scope.ServiceProvider.GetRequiredService<TestBankContext>();
114114
if (bankContext.Database.IsRelational()) {
115-
bankContext.Database.Migrate();
115+
await bankContext.Database.MigrateAsync(cancellationToken);
116116
}
117117
//else {
118118
// await bankContext.Database.EnsureCreatedAsync(cancellationToken);

TestHosts/TestHosts/TestHosts.csproj

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,22 @@
1313
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="9.0.0" />
1414
<PackageReference Include="CoreWCF.Http" Version="1.8.0" />
1515
<PackageReference Include="CoreWCF.Primitives" Version="1.8.0" />
16-
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="10.0.3" />
17-
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.3" />
18-
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.3" />
19-
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.3" />
20-
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="10.0.3" />
16+
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="10.0.5" />
17+
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.5" />
18+
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.5" />
19+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.5" />
20+
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="10.0.5" />
2121
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
2222
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="10.0.2" />
23-
<PackageReference Include="NLog.Web.AspNetCore" Version="6.1.1" />
24-
<PackageReference Include="Shared" Version="2026.2.2" />
25-
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.4" />
23+
<PackageReference Include="NLog.Web.AspNetCore" Version="6.1.2" />
24+
<PackageReference Include="Shared" Version="2026.3.1" />
25+
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.5" />
2626

27-
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.3">
27+
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.5">
2828
<PrivateAssets>all</PrivateAssets>
2929
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
3030
</PackageReference>
31-
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.3">
31+
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.5">
3232
<PrivateAssets>all</PrivateAssets>
3333
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
3434
</PackageReference>

0 commit comments

Comments
 (0)