feat(worker,ui): wire EF Core into DI and update all consumers to IDbContextFactory
Worker and App Program.cs: replace SqliteConnectionFactory+SchemaInitializer with AddDbContextFactory<ClaudeDoDbContext> + Database.Migrate(). Repos changed from AddSingleton to AddScoped. All singleton services (QueueService, StaleTaskRecovery, WorktreeManager, TaskRunner) and singleton ViewModels (MainWindowViewModel, TaskDetailViewModel, TaskListViewModel, TaskEditorViewModel) now take IDbContextFactory<ClaudeDoDbContext> and create short-lived contexts per operation. Test infrastructure: DbFixture now uses EF migrations instead of SchemaInitializer; all test classes create contexts via DbFixture.CreateContext(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ using ClaudeDo.Data.Repositories;
|
||||
using ClaudeDo.Ui;
|
||||
using ClaudeDo.Ui.Services;
|
||||
using ClaudeDo.Ui.ViewModels;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
|
||||
@@ -18,9 +19,10 @@ sealed class Program
|
||||
var services = BuildServices();
|
||||
App.Services = services;
|
||||
|
||||
// Ensure DB schema exists
|
||||
var factory = services.GetRequiredService<SqliteConnectionFactory>();
|
||||
SchemaInitializer.Apply(factory);
|
||||
using (var scope = services.CreateScope())
|
||||
{
|
||||
scope.ServiceProvider.GetRequiredService<ClaudeDoDbContext>().Database.Migrate();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@@ -55,14 +57,10 @@ sealed class Program
|
||||
|
||||
// Infrastructure
|
||||
sc.AddSingleton(settings);
|
||||
sc.AddSingleton(new SqliteConnectionFactory(dbPath));
|
||||
|
||||
// Repositories
|
||||
sc.AddSingleton<ListRepository>();
|
||||
sc.AddSingleton<TaskRepository>();
|
||||
sc.AddSingleton<SubtaskRepository>();
|
||||
sc.AddSingleton<TagRepository>();
|
||||
sc.AddSingleton<WorktreeRepository>();
|
||||
sc.AddDbContextFactory<ClaudeDoDbContext>(opt =>
|
||||
opt.UseSqlite($"Data Source={dbPath}"));
|
||||
sc.AddScoped<ClaudeDoDbContext>(sp =>
|
||||
sp.GetRequiredService<IDbContextFactory<ClaudeDoDbContext>>().CreateDbContext());
|
||||
|
||||
// Services
|
||||
sc.AddSingleton<GitService>();
|
||||
@@ -72,30 +70,21 @@ sealed class Program
|
||||
sc.AddTransient<ListEditorViewModel>();
|
||||
sc.AddTransient<TaskEditorViewModel>();
|
||||
sc.AddSingleton<StatusBarViewModel>();
|
||||
sc.AddSingleton<TaskDetailViewModel>(sp => new TaskDetailViewModel(
|
||||
sp.GetRequiredService<TaskRepository>(),
|
||||
sp.GetRequiredService<WorktreeRepository>(),
|
||||
sp.GetRequiredService<ListRepository>(),
|
||||
sp.GetRequiredService<GitService>(),
|
||||
sp.GetRequiredService<WorkerClient>(),
|
||||
sp.GetRequiredService<TagRepository>(),
|
||||
sp.GetRequiredService<SubtaskRepository>()));
|
||||
sc.AddSingleton<TaskDetailViewModel>();
|
||||
sc.AddSingleton<TaskListViewModel>(sp =>
|
||||
{
|
||||
var taskRepo = sp.GetRequiredService<TaskRepository>();
|
||||
var tagRepo = sp.GetRequiredService<TagRepository>();
|
||||
var listRepo = sp.GetRequiredService<ListRepository>();
|
||||
var dbFactory = sp.GetRequiredService<IDbContextFactory<ClaudeDoDbContext>>();
|
||||
var worker = sp.GetRequiredService<WorkerClient>();
|
||||
var statusBar = sp.GetRequiredService<StatusBarViewModel>();
|
||||
return new TaskListViewModel(
|
||||
taskRepo, tagRepo, listRepo, worker,
|
||||
dbFactory, worker,
|
||||
() => sp.GetRequiredService<TaskEditorViewModel>(),
|
||||
msg => statusBar.ShowMessage(msg));
|
||||
});
|
||||
sc.AddSingleton<MainWindowViewModel>(sp =>
|
||||
{
|
||||
return new MainWindowViewModel(
|
||||
sp.GetRequiredService<ListRepository>(),
|
||||
sp.GetRequiredService<IDbContextFactory<ClaudeDoDbContext>>(),
|
||||
sp.GetRequiredService<WorkerClient>(),
|
||||
sp.GetRequiredService<TaskListViewModel>(),
|
||||
sp.GetRequiredService<TaskDetailViewModel>(),
|
||||
|
||||
Reference in New Issue
Block a user