2023-01-22 18:35:57 +00:00
using DataModel.Database ;
using DataModel.Database.Common ;
2022-11-06 20:07:41 +00:00
using DataModel.MigrationScripts ;
2022-06-12 15:16:01 +00:00
using Microsoft.EntityFrameworkCore ;
using Microsoft.Extensions.DependencyInjection ;
using Microsoft.Extensions.Hosting ;
namespace DataModel ;
public static class Setup
{
private const string ENV_EF_TOOLING_DATABASE = "ENV_EF_TOOLING_DATABASE" ;
private const string DB_READ_WRITE_MODE = "ReadWrite" ;
private const string DB_READ_WRITE_CREATE_MODE = "ReadWriteCreate" ;
2023-01-22 18:35:57 +00:00
private static string USED_DATA_FILE = string . Empty ;
private static SetupMaintenance SETUP_MAINTENANCE = new ( ) ;
public static string DataFile = > Setup . USED_DATA_FILE ;
public static SetupMaintenance Maintenance = > Setup . SETUP_MAINTENANCE ;
2022-07-17 10:54:37 +00:00
2022-06-12 15:16:01 +00:00
/// <summary>
2023-01-18 18:59:18 +00:00
/// Tries to migrate the database.
2022-06-12 15:16:01 +00:00
/// </summary>
public static async Task PerformDataMigration ( DataContext dbContext )
{
var pendingMigrations = ( await dbContext . Database . GetPendingMigrationsAsync ( ) ) . ToList ( ) ;
foreach ( var pendingMigration in pendingMigrations )
{
Console . WriteLine ( $"The migration '{pendingMigration}' is pending." ) ;
}
await dbContext . Database . MigrateAsync ( ) ;
2022-11-06 20:07:41 +00:00
//
// Post migration actions:
//
if ( pendingMigrations . Contains ( "20221106193544_202211AddUniqueIds" ) )
await Script202211AddUniqueIds . PostMigrationAsync ( dbContext ) ;
2022-06-12 15:16:01 +00:00
}
2023-01-18 18:59:18 +00:00
2022-06-12 15:16:01 +00:00
/// <summary>
2023-01-22 18:35:57 +00:00
/// Imports a JSON file into a new database.
2022-06-12 15:16:01 +00:00
/// </summary>
2023-01-22 18:35:57 +00:00
public static async Task ImportDataAndAddDatabase ( this IServiceCollection serviceCollection , string path2JSONFile )
2022-06-12 15:16:01 +00:00
{
2023-01-22 18:35:57 +00:00
var tempPath = Path . GetTempFileName ( ) ;
Setup . USED_DATA_FILE = tempPath ;
Setup . SETUP_MAINTENANCE = new ( path2JSONFile , true ) ;
serviceCollection . AddDbContext < DataContext > ( options = > options . UseSqlite ( $"Filename={tempPath};Mode={DB_READ_WRITE_CREATE_MODE};" ) , ServiceLifetime . Transient ) ;
// Get the database service:
await using var serviceProvider = serviceCollection . BuildServiceProvider ( ) ;
var dbContext = serviceProvider . GetRequiredService < DataContext > ( ) ;
// Next, we import the data from the provided JSON file:
await dbContext . ImportAsync ( path2JSONFile ) ;
//
// Next, we enable the auto-export feature to keep the source file up to date.
// The auto-export feature might exist, but we enforce it, when we work with a
// temporary database source by a JSON file.
//
// Enable the auto-export feature:
var autoExportEnabled = await dbContext . Settings . FirstAsync ( n = > n . Code = = SettingNames . AUTO_EXPORT_ENABLED ) ;
autoExportEnabled . BoolValue = true ;
// Set the auto-export path and file:
var autoExportPath = await dbContext . Settings . FirstAsync ( n = > n . Code = = SettingNames . AUTO_EXPORT_DESTINATION_PATH ) ;
autoExportPath . TextValue = Path . GetDirectoryName ( path2JSONFile ) ? ? string . Empty ;
var autoExportFile = await dbContext . Settings . FirstAsync ( n = > n . Code = = SettingNames . AUTO_EXPORT_FILENAME ) ;
autoExportFile . TextValue = Path . GetFileName ( path2JSONFile ) ;
// Save the changes:
await dbContext . SaveChangesAsync ( ) ;
2022-06-12 15:16:01 +00:00
}
2022-08-17 19:00:58 +00:00
/// <summary>
2023-01-22 18:35:57 +00:00
/// Creates and adds the database instance to the DI system (extension method).
2022-08-17 19:00:58 +00:00
/// </summary>
2023-01-22 18:35:57 +00:00
public static void AddDatabase ( this IServiceCollection serviceCollection , string path2DataFile , bool createWhenNecessary = true )
2022-08-17 19:00:58 +00:00
{
2023-01-22 18:35:57 +00:00
Setup . USED_DATA_FILE = path2DataFile ;
Setup . SETUP_MAINTENANCE = new ( path2DataFile , false ) ;
serviceCollection . AddDbContext < DataContext > ( options = > options . UseSqlite ( $"Filename={path2DataFile};Mode={(createWhenNecessary ? DB_READ_WRITE_CREATE_MODE : DB_READ_WRITE_MODE)};" ) , ServiceLifetime . Transient ) ;
2022-08-17 19:00:58 +00:00
}
2022-06-12 15:16:01 +00:00
/// <summary>
/// Sets up the DI & db context ready for the EF tooling.
/// </summary>
public static IHostBuilder Setup4EFTooling ( string [ ] args )
{
var dataFile = Environment . GetEnvironmentVariable ( ENV_EF_TOOLING_DATABASE ) ;
if ( string . IsNullOrWhiteSpace ( dataFile ) )
{
Console . WriteLine ( "In order to use EF tooling, point the environment variable ENV_EF_TOOLING_DATABASE to the data file, which should be used for the EF tooling." ) ;
Environment . Exit ( 100 ) ;
}
var builder = Host . CreateDefaultBuilder ( args ) ;
builder . ConfigureServices ( ( hostContext , serviceCollection ) = >
{
serviceCollection . AddDbContext < DataContext > ( options = > options . UseSqlite ( $"Filename={dataFile};Mode=ReadWriteCreate" ) ) ;
} ) ;
return builder ;
}
2023-01-22 18:35:57 +00:00
public readonly record struct SetupMaintenance ( string PathToDataFile = "" , bool RemoveTempDatabaseAfterwards = false ) : IDisposable
{
public void Dispose ( )
{
if ( ! this . RemoveTempDatabaseAfterwards )
return ;
try
{
File . Delete ( this . PathToDataFile ) ;
}
catch ( Exception e )
{
Console . WriteLine ( $"Failed to remove the temporary database file: {e.Message} // {e.InnerException?.Message}" ) ;
}
}
}
2022-06-12 15:16:01 +00:00
}