fix(data): address code review findings
- Fix sort order regression in GetByListIdAsync (was descending, should be ascending) - Restore WAL mode pragma (was silently dropped in EF migration) - Add existing-DB compatibility shim in MigrateAndConfigure (baselines InitialCreate migration for databases created by the old schema.sql) - Remove dead AddDbContext/AddScoped registrations from Worker (only IDbContextFactory is used by singleton consumers) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,7 +21,8 @@ sealed class Program
|
|||||||
|
|
||||||
using (var scope = services.CreateScope())
|
using (var scope = services.CreateScope())
|
||||||
{
|
{
|
||||||
scope.ServiceProvider.GetRequiredService<ClaudeDoDbContext>().Database.Migrate();
|
ClaudeDoDbContext.MigrateAndConfigure(
|
||||||
|
scope.ServiceProvider.GetRequiredService<ClaudeDoDbContext>());
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using ClaudeDo.Data.Models;
|
using ClaudeDo.Data.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
|
||||||
namespace ClaudeDo.Data;
|
namespace ClaudeDo.Data;
|
||||||
|
|
||||||
@@ -19,4 +21,44 @@ public class ClaudeDoDbContext : DbContext
|
|||||||
{
|
{
|
||||||
modelBuilder.ApplyConfigurationsFromAssembly(typeof(ClaudeDoDbContext).Assembly);
|
modelBuilder.ApplyConfigurationsFromAssembly(typeof(ClaudeDoDbContext).Assembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies EF Core migrations and sets WAL mode. Safe for both fresh and existing databases.
|
||||||
|
/// Existing databases (created by the old schema.sql) have their tables but no
|
||||||
|
/// __EFMigrationsHistory — this method detects that case and baselines the initial
|
||||||
|
/// migration so EF skips re-creating tables that already exist.
|
||||||
|
/// </summary>
|
||||||
|
public static void MigrateAndConfigure(ClaudeDoDbContext db)
|
||||||
|
{
|
||||||
|
// If the 'lists' table exists but __EFMigrationsHistory does not,
|
||||||
|
// this is a pre-EF database. Baseline the InitialCreate migration.
|
||||||
|
var conn = db.Database.GetDbConnection();
|
||||||
|
conn.Open();
|
||||||
|
using (var cmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
cmd.CommandText = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='lists'";
|
||||||
|
var hasLists = Convert.ToInt64(cmd.ExecuteScalar()) > 0;
|
||||||
|
|
||||||
|
cmd.CommandText = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='__EFMigrationsHistory'";
|
||||||
|
var hasHistory = Convert.ToInt64(cmd.ExecuteScalar()) > 0;
|
||||||
|
|
||||||
|
if (hasLists && !hasHistory)
|
||||||
|
{
|
||||||
|
// Create the history table and mark InitialCreate as applied.
|
||||||
|
cmd.CommandText = """
|
||||||
|
CREATE TABLE "__EFMigrationsHistory" (
|
||||||
|
"MigrationId" TEXT NOT NULL CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY,
|
||||||
|
"ProductVersion" TEXT NOT NULL
|
||||||
|
);
|
||||||
|
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||||
|
VALUES ('20260416064948_InitialCreate', '8.0.11');
|
||||||
|
""";
|
||||||
|
cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn.Close();
|
||||||
|
|
||||||
|
db.Database.Migrate();
|
||||||
|
db.Database.ExecuteSqlRaw("PRAGMA journal_mode=WAL");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public sealed class TaskRepository
|
|||||||
{
|
{
|
||||||
return await _context.Tasks
|
return await _context.Tasks
|
||||||
.Where(t => t.ListId == listId)
|
.Where(t => t.ListId == listId)
|
||||||
.OrderByDescending(t => t.CreatedAt)
|
.OrderBy(t => t.CreatedAt)
|
||||||
.ToListAsync(ct);
|
.ToListAsync(ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public sealed class InitDatabaseStep : IInstallStep
|
|||||||
.UseSqlite($"Data Source={expandedPath}")
|
.UseSqlite($"Data Source={expandedPath}")
|
||||||
.Options;
|
.Options;
|
||||||
using var context = new ClaudeDoDbContext(options);
|
using var context = new ClaudeDoDbContext(options);
|
||||||
context.Database.Migrate();
|
ClaudeDoDbContext.MigrateAndConfigure(context);
|
||||||
|
|
||||||
progress.Report("Schema applied successfully");
|
progress.Report("Schema applied successfully");
|
||||||
return Task.FromResult(StepResult.Ok());
|
return Task.FromResult(StepResult.Ok());
|
||||||
|
|||||||
@@ -17,16 +17,8 @@ builder.Host.UseWindowsService(o => o.ServiceName = "ClaudeDoWorker");
|
|||||||
|
|
||||||
builder.Services.AddDbContextFactory<ClaudeDoDbContext>(opt =>
|
builder.Services.AddDbContextFactory<ClaudeDoDbContext>(opt =>
|
||||||
opt.UseSqlite($"Data Source={cfg.DbPath}"));
|
opt.UseSqlite($"Data Source={cfg.DbPath}"));
|
||||||
builder.Services.AddDbContext<ClaudeDoDbContext>(opt =>
|
|
||||||
opt.UseSqlite($"Data Source={cfg.DbPath}"));
|
|
||||||
|
|
||||||
builder.Services.AddSingleton(cfg);
|
builder.Services.AddSingleton(cfg);
|
||||||
builder.Services.AddScoped<TagRepository>();
|
|
||||||
builder.Services.AddScoped<ListRepository>();
|
|
||||||
builder.Services.AddScoped<TaskRepository>();
|
|
||||||
builder.Services.AddScoped<SubtaskRepository>();
|
|
||||||
builder.Services.AddScoped<WorktreeRepository>();
|
|
||||||
builder.Services.AddScoped<TaskRunRepository>();
|
|
||||||
builder.Services.AddHostedService<StaleTaskRecovery>();
|
builder.Services.AddHostedService<StaleTaskRecovery>();
|
||||||
builder.Services.AddSignalR();
|
builder.Services.AddSignalR();
|
||||||
|
|
||||||
@@ -54,7 +46,8 @@ var app = builder.Build();
|
|||||||
|
|
||||||
using (var scope = app.Services.CreateScope())
|
using (var scope = app.Services.CreateScope())
|
||||||
{
|
{
|
||||||
scope.ServiceProvider.GetRequiredService<ClaudeDoDbContext>().Database.Migrate();
|
ClaudeDoDbContext.MigrateAndConfigure(
|
||||||
|
scope.ServiceProvider.GetRequiredService<ClaudeDoDbContext>());
|
||||||
}
|
}
|
||||||
|
|
||||||
app.MapHub<WorkerHub>("/hub");
|
app.MapHub<WorkerHub>("/hub");
|
||||||
|
|||||||
Reference in New Issue
Block a user