diff --git a/DataStore/DatabaseService.cs b/DataStore/DatabaseService.cs new file mode 100644 index 0000000..06e6f42 --- /dev/null +++ b/DataStore/DatabaseService.cs @@ -0,0 +1,166 @@ +using System; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace Logof_Client; + +/// +/// Zentrale Datenbankverwaltung für Logof Client. +/// +/// Zuständig für: +/// - PostgreSQL-Verbindung +/// - EF Core DbContext +/// - Datenbankmodelle +/// - Migrationen +/// - Verbindungstest +/// +public static class DatabseService +{ + private static DbContextOptions? _options; + + /// + /// Initialisiert die Datenbankverbindung. + /// Sollte einmal beim Programmstart aufgerufen werden. + /// + public static void Initialize(string connectionString) + { + if (string.IsNullOrWhiteSpace(connectionString)) + throw new ArgumentException( + "Kein Datenbank-Connection-String angegeben.", + nameof(connectionString)); + + var builder = new DbContextOptionsBuilder(); + + builder.UseNpgsql(connectionString); + + _options = builder.Options; + } + + /// + /// Erstellt einen neuen DbContext. + /// + public static LogofDbContext GetContext() + { + if (_options == null) + throw new InvalidOperationException( + "DB wurde noch nicht initialisiert. " + + "Rufen Sie DB.Initialize(...) auf."); + + return new LogofDbContext(_options); + } + + /// + /// Testet die Verbindung zum Datenbankserver. + /// + public static async Task TestConnectionAsync() + { + try + { + await using var db = GetContext(); + return await db.Database.CanConnectAsync(); + } + catch + { + return false; + } + } + + /// + /// Erstellt bzw. aktualisiert das Datenbankschema + /// anhand der vorhandenen EF-Core-Migrationen. + /// + public static async Task MigrateAsync() + { + await using var db = GetContext(); + + await db.Database.MigrateAsync(); + } +} + + +// ============================================================================ +// DATABASE CONTEXT +// ============================================================================ + +public class LogofDbContext : DbContext +{ + public DbSet Customers => Set(); + + public LogofDbContext( + DbContextOptions options) + : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + // -------------------------------------------------------------------- + // Customer + // -------------------------------------------------------------------- + + modelBuilder.Entity(entity => + { + entity.ToTable("customers"); + + entity.HasKey(x => x.Id); + + entity.Property(x => x.Id) + .ValueGeneratedOnAdd(); + + entity.Property(x => x.Name) + .HasMaxLength(255) + .IsRequired(); + + entity.Property(x => x.Description) + .HasMaxLength(4000); + + entity.Property(x => x.SenderAddress) + .HasMaxLength(4000); + + entity.Property(x => x.Separator) + .HasMaxLength(1) + .IsRequired(); + + // Optimistic Concurrency + entity.Property(x => x.Version) + .IsConcurrencyToken(); + + entity.Property(x => x.CreatedAt) + .IsRequired(); + + entity.Property(x => x.UpdatedAt) + .IsRequired(); + }); + } +} + + +// ============================================================================ +// DATABASE MODELS +// ============================================================================ + +public class CustomerEx +{ + public long Id { get; set; } + + public string Name { get; set; } = ""; + + public string Description { get; set; } = ""; + + public string SenderAddress { get; set; } = ""; + + public char Separator { get; set; } = ','; + + /// + /// Wird bei jeder Änderung erhöht. + /// Verhindert, dass zwei Benutzer sich gegenseitig + /// Änderungen überschreiben. + /// + public long Version { get; set; } = 1; + + public DateTime CreatedAt { get; set; } + + public DateTime UpdatedAt { get; set; } +} \ No newline at end of file