using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; using SmartStack.Infrastructure.Persistence; namespace {{ProjectName}}.Infrastructure.Persistence; /// /// Factory for creating ExtensionsDbContext at design time (for EF Core CLI tools). /// /// This enables running migrations from the command line: /// /// dotnet ef migrations add MyMigration --context ExtensionsDbContext /// dotnet ef database update --context ExtensionsDbContext /// dotnet ef migrations list --context ExtensionsDbContext /// dotnet ef migrations script --context ExtensionsDbContext -o deploy.sql /// /// /// IMPORTANT: Migrations are stored in the 'extensions' schema, separate from /// SmartStack Core migrations in the 'core' schema. The Core whitelist entities /// exposed by SmartStackExtensionDbContext are mapped via /// ExcludeFromMigrations — they are visible at runtime for FK resolution /// but NEVER appear in the migrations this factory generates. /// /// At design time we pass null for ICurrentTenantService — query /// filters apply only at runtime; the migration generator ignores them. /// public class DesignTimeExtensionsDbContextFactory : IDesignTimeDbContextFactory { public ExtensionsDbContext 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 => { b.MigrationsAssembly(typeof(ExtensionsDbContext).Assembly.FullName); // IMPORTANT: Store migrations history in 'extensions' schema // This keeps client migrations separate from Core migrations b.MigrationsHistoryTable("__EFMigrationsHistory", SchemaConstants.Extensions); }); // tenantService = null at design time — query filters apply at runtime only. return new ExtensionsDbContext(optionsBuilder.Options, tenantService: null); } }