using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using SmartStack.Infrastructure.Persistence;
using SmartStack.Infrastructure.Persistence.Configurations;
namespace {{ProjectName}}.Api.Persistence;
///
/// Factory for creating the SmartStack CoreDbContext at design time (for EF Core CLI tools).
///
/// The concrete CoreDbContext type lives in the SmartStack NuGet package. EF's design-time
/// discovery only scans the startup assembly (this project) and the --project assembly for
/// context types and factories — never referenced packages — so without this factory,
/// `dotnet ef` (and the deploy pipeline's migration-bundle build) can only see
/// ExtensionsDbContext and the Core migrations never ship in a bundle.
///
/// It MUST live in the STARTUP assembly (the Api): EF's initial factory scan only covers
/// the startup assembly, and that scan is the only discovery path for a context type
/// defined in a referenced package.
///
/// This enables running Core migrations from the command line / CI:
///
/// dotnet ef migrations bundle --context CoreDbContext --startup-project src/{{ProjectName}}.Api
/// dotnet ef migrations list --context CoreDbContext --startup-project src/{{ProjectName}}.Api
///
///
/// IMPORTANT: Core migrations come from the SmartStack package assembly and live in the
/// 'core' schema, separate from client migrations in the 'extensions' schema. Apply Core
/// BEFORE Extensions — extensions.* tables carry FKs into core.* tables.
///
public class DesignTimeCoreDbContextFactory : IDesignTimeDbContextFactory
{
public CoreDbContext CreateDbContext(string[] args)
{
// Try to find appsettings.json in various locations
var basePath = Directory.GetCurrentDirectory();
// Look for appsettings.json in common locations
var configPaths = new[]
{
basePath,
Path.Combine(basePath, "..", "{{ProjectName}}.Api"),
Path.Combine(basePath, "..", "..", "src", "{{ProjectName}}.Api"),
};
IConfigurationRoot? configuration = null;
foreach (var path in configPaths)
{
var configPath = Path.Combine(path, "appsettings.json");
if (File.Exists(configPath))
{
configuration = new ConfigurationBuilder()
.SetBasePath(path)
.AddJsonFile("appsettings.json", optional: false)
.AddJsonFile("appsettings.Development.json", optional: true)
.AddJsonFile("appsettings.Local.json", optional: true)
.Build();
break;
}
}
// Fallback: use a default connection string for design-time operations
var connectionString = configuration?.GetConnectionString("DefaultConnection")
?? "Server=(localdb)\\mssqllocaldb;Database={{ProjectName}}_DesignTime;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True";
var optionsBuilder = new DbContextOptionsBuilder();
optionsBuilder.UseSqlServer(connectionString, b =>
{
// Core migrations are compiled into the SmartStack package assembly
b.MigrationsAssembly(typeof(CoreDbContext).Assembly.FullName);
// IMPORTANT: Core migrations history lives in the 'core' schema
b.MigrationsHistoryTable("__EFMigrationsHistory", SchemaConstants.Core);
});
return new CoreDbContext(optionsBuilder.Options);
}
}