Files
DbFirst/docs/PROJEKTDOKUMENTATION.md
OlgunR cdf225bad1 Add full project documentation (PROJEKTDOKUMENTATION.md)
Comprehensive documentation for the DbFirst solution, detailing project goals, architecture (Clean Architecture), technology stack, solution/project structure, Database-First approach, CQRS with MediatR, API endpoints, Blazor/DevExpress frontend, dashboard and layout persistence, SignalR integration, configuration, development setup, architecture decisions (ADRs), extensibility, and glossary. Includes diagrams, code snippets, and workflow guidance for the developer team.
2026-04-09 15:45:32 +02:00

47 KiB
Raw Blame History

DbFirst Projektdokumentation

Version: 1.0
Stand: Juli 2025
Repository: https://git.dd/AppStd/DbFirst (Branch: main)
Zielgruppe: Entwickler-Team


Inhaltsverzeichnis

  1. Projektziel & Motivation
  2. Technologie-Stack
  3. Architekturübersicht (Clean Architecture)
  4. Solution-Struktur
  5. Projekt-Details
  6. Abhängigkeiten zwischen Projekten
  7. Database-First-Ansatz & Scaffold-Befehl
  8. Datenbank-Architektur
  9. CQRS-Pattern (MediatR)
  10. API-Endpunkte
  11. Blazor-Frontend & DevExpress
  12. Dashboard-System (DevExpress Dashboards)
  13. Layout-Persistierung
  14. Echtzeit-Kommunikation (SignalR)
  15. Konfiguration
  16. Lokale Entwicklungsumgebung
  17. Architektur-Entscheidungen (ADRs)
  18. Erweiterbarkeit & nächste Schritte
  19. Glossar

1. Projektziel & Motivation

Ausgangslage

Es existiert eine bestehende Produktions-Datenbank (DD_ECM) mit etablierten Tabellen, Views und Stored Procedures. Die bisherige Software, die auf diese Datenbank zugreift, soll durch eine moderne Webanwendung abgelöst werden.

Ziele

# Ziel Beschreibung
1 Backend-Modernisierung EF Core im Database-First-Ansatz auf einer bestehenden Produktions-DB einsetzen. Kein Code-First, keine Migrationen die Datenbank bleibt die „Source of Truth".
2 Clean Architecture & DDD Strukturierung des Backends nach Prinzipien der Clean Architecture und Domain-Driven Design mit klar getrennten Schichten.
3 Frontend-Evaluation Blazor Web App (.NET 8) in Kombination mit DevExpress Blazor evaluieren Grids, Dashboards, Theming um den Fit für den produktiven Einsatz zu testen.
4 Best Practices CQRS via MediatR, AutoMapper, Repository-Pattern, globales Exception Handling, CORS-Konfiguration, Echtzeit-Updates via SignalR.

Nicht-Ziele (bewusst ausgeklammert)

  • EF Core Migrations / Code-First
  • Authentifizierung & Autorisierung (noch nicht implementiert)
  • Deployment / CI/CD Pipeline (noch nicht konfiguriert)

2. Technologie-Stack

Backend

Technologie Version Zweck
.NET 8.0 Runtime & SDK
ASP.NET Core Web API 8.0 REST-API
Entity Framework Core 8.0.22 ORM (Database-First)
Microsoft.Data.SqlClient 5.2.1 SQL Server Zugriff (Stored Procedures)
MediatR 11.1.0 CQRS-Pattern
AutoMapper 12.0.1 Entity ? DTO Mapping
Swashbuckle (Swagger) 6.6.2 API-Dokumentation
DevExpress Dashboard (ASP.NET Core) 25.2.3 Server-seitiges Dashboard-Backend
SignalR 8.0.22 Echtzeit-Benachrichtigungen

Frontend

Technologie Version Zweck
Blazor Web App .NET 8 UI-Framework (Interactive Server Rendering)
DevExpress Blazor 25.2.3 UI-Komponentenbibliothek (Grid, Forms, etc.)
DevExpress Blazor Dashboard 25.2.3 Dashboard-Viewer & -Designer im Frontend
DevExpress Blazor Themes (Fluent) 25.2.3 Theming (Light/Dark Mode)
SignalR Client 8.0.22 Echtzeit-Empfang

Datenbank

Technologie Zweck
Microsoft SQL Server Produktionsdatenbank (DD_ECM)
Views (VWMY_CATALOG) Leseoperationen
Stored Procedures (PRTBMY_CATALOG_*) Schreiboperationen (Insert, Update, Delete)

3. Architekturübersicht (Clean Architecture)

????????????????????????????????????????????????????????????????
?                    Präsentationsschicht                       ?
?  ???????????????????????    ????????????????????????????     ?
?  ?  DbFirst.BlazorWebApp?    ?      DbFirst.API         ?     ?
?  ?  (Blazor Frontend)  ??????  (ASP.NET Core Web API)  ?     ?
?  ?  Port: 7191         ?HTTP?  Port: 7204              ?     ?
?  ???????????????????????    ????????????????????????????     ?
?                                        ?                     ?
????????????????????????????????????????????????????????????????
?                 Anwendungsschicht      ?                     ?
?  ??????????????????????????????????????????????????????      ?
?  ?              DbFirst.Application                   ?      ?
?  ?  Commands, Queries, Handlers (MediatR/CQRS)        ?      ?
?  ?  DTOs, AutoMapper Profiles, Repository-Interfaces  ?      ?
?  ??????????????????????????????????????????????????????      ?
?                                        ?                     ?
????????????????????????????????????????????????????????????????
?                  Domänenschicht        ?                     ?
?  ??????????????????????????????????????????????????????      ?
?  ?                DbFirst.Domain                      ?      ?
?  ?  Entities, Enums (keine Abhängigkeiten!)           ?      ?
?  ??????????????????????????????????????????????????????      ?
?                                                              ?
????????????????????????????????????????????????????????????????
?               Infrastrukturschicht                           ?
?  ??????????????????????????????????????????????????????      ?
?  ?            DbFirst.Infrastructure                  ?      ?
?  ?  DbContext, Repository-Implementierungen,          ?      ?
?  ?  EF Core Konfiguration, DB-Zugriff                 ?      ?
?  ??????????????????????????????????????????????????????      ?
?                                   ?                          ?
?                              ???????????                     ?
?                              ? SQL     ?                     ?
?                              ? Server  ?                     ?
?                              ? (DD_ECM)?                     ?
?                              ???????????                     ?
????????????????????????????????????????????????????????????????

Dependency Rule (Abhängigkeitsregel)

Die zentrale Regel der Clean Architecture wird eingehalten:

  • Domain hat keine Abhängigkeiten zu anderen Projekten.
  • Application kennt nur Domain (und definiert Interfaces).
  • Infrastructure implementiert die Interfaces aus Application und referenziert Domain + Application.
  • API orchestriert alles und referenziert Application, Infrastructure und Domain.
  • BlazorWebApp kommuniziert ausschließlich via HTTP mit der API kein direkter Zugriff auf Domain, Application oder Infrastructure.

4. Solution-Struktur

DbFirst/                                    ? Solution-Root
?
??? docs/
?   ??? PROJEKTDOKUMENTATION.md             ? Diese Datei
?
??? DbFirst.Domain/                         ? Domänenschicht (Kern)
?   ??? Entities/
?   ?   ??? VwmyCatalog.cs                  ? Katalog-Entity (aus VWMY_CATALOG View)
?   ?   ??? SmfLayout.cs                    ? Layout-Entity (TBDD_SMF_LAYOUT Tabelle)
?   ?   ??? Massdata.cs                     ? MassData-Entity (MASSDATA Tabelle)
?   ??? CatalogUpdateProcedure.cs           ? Enum: Update vs. Save
?   ??? DbFirst.Domain.csproj
?
??? DbFirst.Application/                    ? Anwendungsschicht
?   ??? Catalogs/
?   ?   ??? CatalogReadDto.cs               ? Read-DTO
?   ?   ??? CatalogWriteDto.cs              ? Write-DTO (inkl. UpdateProcedure)
?   ?   ??? CatalogProfile.cs              ? AutoMapper-Profil
?   ?   ??? Commands/
?   ?   ?   ??? CreateCatalogCommand.cs     ? MediatR Command
?   ?   ?   ??? CreateCatalogHandler.cs     ? MediatR Handler
?   ?   ?   ??? UpdateCatalogCommand.cs
?   ?   ?   ??? UpdateCatalogHandler.cs
?   ?   ?   ??? DeleteCatalogCommand.cs
?   ?   ?   ??? DeleteCatalogHandler.cs
?   ?   ??? Queries/
?   ?       ??? GetAllCatalogsQuery.cs
?   ?       ??? GetAllCatalogsHandler.cs
?   ?       ??? GetCatalogByIdQuery.cs
?   ?       ??? GetCatalogByIdHandler.cs
?   ??? MassData/
?   ?   ??? MassDataReadDto.cs
?   ?   ??? MassDataWriteDto.cs
?   ?   ??? MassDataProfile.cs
?   ?   ??? Commands/
?   ?   ?   ??? UpsertMassDataByCustomerNameCommand.cs
?   ?   ?   ??? UpsertMassDataByCustomerNameHandler.cs
?   ?   ??? Queries/
?   ?       ??? GetAllMassDataQuery.cs      ? Paginierung (Skip/Take)
?   ?       ??? GetAllMassDataHandler.cs
?   ?       ??? GetMassDataCountQuery.cs
?   ?       ??? GetMassDataCountHandler.cs
?   ?       ??? GetMassDataByCustomerNameQuery.cs
?   ?       ??? GetMassDataByCustomerNameHandler.cs
?   ??? Repositories/
?   ?   ??? IRepository.cs                  ? Generisches Basis-Interface
?   ?   ??? ICatalogRepository.cs           ? Erweitert IRepository<VwmyCatalog>
?   ?   ??? IMassDataRepository.cs          ? Eigenes Interface (kein IRepository)
?   ?   ??? ILayoutRepository.cs            ? Eigenes Interface
?   ??? DependencyInjection.cs              ? AddApplication() Extension
?   ??? DbFirst.Application.csproj
?
??? DbFirst.Infrastructure/                 ? Infrastrukturschicht
?   ??? ApplicationDbContext.cs             ? EF Core DbContext (Catalog, Layout)
?   ??? MassDataDbContext.cs                ? EF Core DbContext (MassData)
?   ??? TableConfigurations.cs              ? Konfigurierbare Tabellen-/Spaltennamen
?   ??? Repositories/
?   ?   ??? CatalogRepository.cs            ? Stored Procedure basiert
?   ?   ??? MassDataRepository.cs           ? Stored Procedure basiert
?   ?   ??? LayoutRepository.cs             ? EF Core basiert (CRUD)
?   ??? DependencyInjection.cs              ? AddInfrastructure() Extension
?   ??? DbFirst.Infrastructure.csproj
?
??? DbFirst.API/                            ? Web API (Startprojekt Backend)
?   ??? Controllers/
?   ?   ??? CatalogsController.cs           ? CRUD via MediatR
?   ?   ??? MassDataController.cs           ? Paginiertes Lesen + Upsert
?   ?   ??? LayoutsController.cs            ? Grid-Layout CRUD
?   ?   ??? DefaultDashboardController.cs   ? DevExpress Dashboard-Controller
?   ??? Dashboards/
?   ?   ??? SqlDashboardStorage.cs          ? Dashboard-Persistierung in SQL
?   ?   ??? IDashboardChangeNotifier.cs     ? Interface für SignalR-Benachrichtigung
?   ?   ??? DashboardChangeNotifier.cs      ? SignalR-basierte Implementierung
?   ??? Hubs/
?   ?   ??? DashboardsHub.cs               ? SignalR Hub für Dashboard-Updates
?   ??? Middleware/
?   ?   ??? ExceptionHandlingMiddleware.cs  ? Globales Exception Handling
?   ??? Program.cs                          ? DI, Middleware, Routing
?   ??? appsettings.json                    ? Connection Strings, CORS, etc.
?   ??? DbFirst.API.csproj
?
??? DbFirst.BlazorWebApp/                   ? Blazor Frontend (Startprojekt Frontend)
?   ??? Components/
?   ?   ??? App.razor                       ? Root-Komponente, DevExpress Themes
?   ?   ??? Routes.razor                    ? Routing
?   ?   ??? _Imports.razor                  ? Globale Using-Direktiven
?   ?   ??? Layout/
?   ?   ?   ??? MainLayout.razor            ? Hauptlayout (Sidebar + Content)
?   ?   ?   ??? MainLayout.razor.css
?   ?   ?   ??? NavMenu.razor               ? Navigation (Home, Catalogs, etc.)
?   ?   ?   ??? NavMenu.razor.css
?   ?   ??? Pages/
?   ?   ?   ??? Home.razor                  ? Startseite mit DxCarousel
?   ?   ?   ??? Catalogs.razor              ? Katalog-Seite
?   ?   ?   ??? Massdata.razor              ? MassData-Seite
?   ?   ?   ??? Dashboard.razor             ? Dashboard Viewer/Designer
?   ?   ?   ??? Dashboard.razor.css
?   ?   ?   ??? Error.razor                 ? Fehlerseite
?   ?   ??? CatalogsGrid.razor              ? Katalog-Grid-Komponente
?   ?   ??? CatalogsGrid.razor.css
?   ?   ??? MassDataGrid.razor              ? MassData-Grid-Komponente
?   ?   ??? MassDataGrid.razor.css
?   ??? Models/
?   ?   ??? CatalogReadDto.cs               ? Frontend-DTO (Spiegelung der API)
?   ?   ??? CatalogWriteDto.cs
?   ?   ??? MassDataReadDto.cs
?   ?   ??? MassDataWriteDto.cs
?   ?   ??? LayoutDto.cs
?   ?   ??? DashboardInfoDto.cs
?   ?   ??? Grid/
?   ?       ??? BandLayoutModels.cs         ? Band-/Spalten-Layout-Modelle
?   ??? Services/
?   ?   ??? CatalogApiClient.cs             ? Typisierter HttpClient (Catalog)
?   ?   ??? MassDataApiClient.cs            ? Typisierter HttpClient (MassData)
?   ?   ??? DashboardApiClient.cs           ? Typisierter HttpClient (Dashboard)
?   ?   ??? LayoutApiClient.cs              ? Typisierter HttpClient (Layout)
?   ?   ??? BandLayoutService.cs            ? Band-Layout Logik (Laden/Speichern)
?   ?   ??? ThemeState.cs                   ? Light/Dark Mode State
?   ??? Program.cs                          ? DI, Middleware, Routing
?   ??? appsettings.json                    ? ApiBaseUrl
?   ??? DbFirst.BlazorWebApp.csproj
?
??? DbFirst.sln                             ? Solution-Datei

5. Projekt-Details

5.1 DbFirst.Domain

Zweck: Enthält die Domänen-Entities und Enums der innerste Kern der Architektur.

Abhängigkeiten: ? Keine (reines .NET 8 Class Library)

Entities

Entity Datenbank-Objekt Beschreibung
VwmyCatalog View VWMY_CATALOG Katalog-Einträge mit Titel, Kennung, Audit-Feldern
SmfLayout Tabelle TBDD_SMF_LAYOUT Persistierte Grid-Layouts pro User
Massdata Tabelle MASSDATA Massendaten mit Kundenname, Betrag, Kategorie, Status

Enums

Enum Werte Beschreibung
CatalogUpdateProcedure Update = 0, Save = 1 Steuert, welche Stored Procedure beim Update aufgerufen wird

Design-Entscheidungen

  • Entities werden durch den EF Core Scaffold generiert und bei Bedarf manuell angepasst.
  • VwmyCatalog ist partial class dadurch kann der Scaffold wiederholt werden, ohne manuelle Erweiterungen zu verlieren (sofern diese in einer separaten Partial-Datei liegen).
  • Entity-Properties verwenden die C#-Namen (PascalCase), das Mapping auf DB-Spaltennamen (UPPER_SNAKE_CASE) erfolgt im DbContext.

5.2 DbFirst.Application

Zweck: Enthält die Geschäftslogik in Form von CQRS Commands/Queries (MediatR), DTOs und AutoMapper-Profile. Definiert die Repository-Interfaces (Dependency Inversion).

Abhängigkeiten: DbFirst.Domain

Packages

Package Zweck
MediatR.Extensions.Microsoft.DependencyInjection CQRS Handler-Registrierung
AutoMapper / AutoMapper.Extensions.Microsoft.DependencyInjection Entity ? DTO Mapping

Struktur nach Feature-Ordner

Application/
??? Catalogs/           ? Feature: Katalogverwaltung
?   ??? Commands/       ? Schreiboperationen (Create, Update, Delete)
?   ??? Queries/        ? Leseoperationen (GetAll, GetById)
?   ??? CatalogReadDto  ? Ausgabe-DTO
?   ??? CatalogWriteDto ? Eingabe-DTO
?   ??? CatalogProfile  ? AutoMapper
??? MassData/           ? Feature: Massendaten
?   ??? Commands/       ? Upsert
?   ??? Queries/        ? GetAll (paginiert), GetCount, GetByCustomerName
?   ??? MassDataReadDto
?   ??? MassDataWriteDto
?   ??? MassDataProfile
??? Repositories/       ? Interface-Definitionen
    ??? IRepository<T>  ? Generisches Basis-Interface
    ??? ICatalogRepository
    ??? IMassDataRepository
    ??? ILayoutRepository

Repository-Interfaces

IRepository<T> Generisches Basis-Interface:

public interface IRepository<T>
{
    Task<List<T>> GetAllAsync(CancellationToken ct);
    Task<T?> GetByIdAsync(int id, CancellationToken ct);
    Task<T> InsertAsync(T entity, CancellationToken ct);
    Task<T?> UpdateAsync(int id, T entity, CancellationToken ct);
    Task<bool> DeleteAsync(int id, CancellationToken ct);
}

ICatalogRepository Erweitert das generische Interface um spezifische Methoden:

public interface ICatalogRepository : IRepository<VwmyCatalog>
{
    Task<VwmyCatalog?> GetByTitleAsync(string title, CancellationToken ct);
    Task<VwmyCatalog?> UpdateAsync(int id, VwmyCatalog catalog, CatalogUpdateProcedure procedure, CancellationToken ct);
}

IMassDataRepository und ILayoutRepository nutzen bewusst nicht IRepository<T>, da deren Operationen stark abweichen (Upsert statt Insert, Suche nach Composite Keys statt int-ID).

DI-Registrierung

public static IServiceCollection AddApplication(this IServiceCollection services)
{
    services.AddAutoMapper(typeof(DependencyInjection).Assembly);
    services.AddMediatR(typeof(DependencyInjection).Assembly);
    return services;
}

5.3 DbFirst.Infrastructure

Zweck: Implementiert die Repository-Interfaces, enthält die EF Core DbContexts und das Datenbank-Mapping.

Abhängigkeiten: DbFirst.Domain, DbFirst.Application

DbContexts

Das Projekt verwendet zwei separate DbContexts:

DbContext Datenbank Verbindung Entities
ApplicationDbContext DD_ECM (SQL17) DefaultConnection VwmyCatalog, SmfLayout
MassDataDbContext DD_ECM (SQL19) MassDataConnection Massdata

Begründung für zwei DbContexts: Die Entities liegen auf verschiedenen SQL-Server-Instanzen (SQL17 vs. SQL19).

Konfigurierbare Tabellen-/Spaltennamen (TableConfigurations)

Die Spaltennamen der VwmyCatalog-View sind über appsettings.json konfigurierbar:

"TableConfigurations": {
  "VwmyCatalog": {
    "ViewName": "VWMY_CATALOG",
    "GuidColumnName": "GUID",
    "CatTitleColumnName": "CAT_TITLE",
    ...
  }
}

Dies erlaubt es, die Anwendung ohne Code-Änderung auf andere DB-Schemata zu zeigen.

Repository-Implementierungen

Repository Lese-Strategie Schreib-Strategie
CatalogRepository EF Core via View (AsNoTracking) Stored Procedures (PRTBMY_CATALOG_INSERT, _UPDATE, _SAVE, _DELETE)
MassDataRepository EF Core via Tabelle (AsNoTracking) mit Paginierung Stored Procedure (PRMassdata_UpsertByCustomerName)
LayoutRepository EF Core via Tabelle EF Core direkt (Add, SaveChanges, Remove)

Wichtig: Bei CatalogRepository und MassDataRepository werden Stored Procedures mit Output-Parametern verwendet. Nach der SP-Ausführung wird der geänderte Datensatz erneut aus der View/Tabelle geladen, um konsistente Daten zurückzugeben.

DI-Registrierung

public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
{
    services.Configure<TableConfigurations>(configuration.GetSection("TableConfigurations"));
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));
    services.AddDbContext<MassDataDbContext>(options =>
        options.UseSqlServer(configuration.GetConnectionString("MassDataConnection")));
    return services;
}

5.4 DbFirst.API

Zweck: REST-API, die als Backend für das Blazor-Frontend dient. Orchestriert DI, Middleware, Routing.

Abhängigkeiten: DbFirst.Domain, DbFirst.Application, DbFirst.Infrastructure

Controller-Übersicht

Controller Route Beschreibung
CatalogsController api/catalogs CRUD für Kataloge via MediatR
MassDataController api/massdata Paginiertes Lesen + Upsert via MediatR
LayoutsController api/layouts Grid-Layout-Verwaltung (direkt via Repository)
DefaultDashboardController api/dashboard DevExpress Dashboard-Backend

Middleware

  • ExceptionHandlingMiddleware: Fängt alle unbehandelten Exceptions, loggt sie und gibt ein standardisiertes JSON-Problem-Details-Objekt zurück (RFC 9110).

CORS-Konfiguration

Development: AllowAnyOrigin, AllowAnyHeader, AllowAnyMethod
Production:  Nur explizit konfigurierte Origins aus appsettings.json
             Wenn keine Origins konfiguriert ? alles blockiert

Dashboard-System

Die API hostet das DevExpress Dashboard Backend und bietet:

  • SqlDashboardStorage: Speichert Dashboards als XML-Blob in einer SQL-Tabelle (TBDD_SMF_CONFIG).
  • Default-Dashboards: Werden beim Start automatisch erstellt, wenn sie nicht in der DB existieren (DefaultDashboard, CatalogsGrid).
  • JSON Data Sources: API-Endpunkte werden als Dashboard-Datenquellen registriert.
  • SignalR Hub (/hubs/dashboards): Benachrichtigt alle Clients bei Dashboard-Änderungen.

5.5 DbFirst.BlazorWebApp

Zweck: Blazor Web App als Frontend. Kommuniziert ausschließlich via HTTP mit der API. Kein direkter DB-Zugriff.

Abhängigkeiten: Keine Projekt-Referenzen! Nur NuGet-Packages. Kommunikation mit dem Backend über HttpClient.

Render-Modus

Die Anwendung nutzt Interactive Server Rendering (@rendermode InteractiveServer). Der gesamte UI-State lebt auf dem Server, der Browser erhält Updates via SignalR (Blazor-intern).

Seiten

Seite Route Beschreibung
Home.razor / Startseite mit DevExpress Carousel (Architektur-Diagramme)
Catalogs.razor /catalogs Einbettung der CatalogsGrid-Komponente
Massdata.razor /massdata Einbettung der MassDataGrid-Komponente
Dashboard.razor /dashboards/{Id?} DevExpress Dashboard Viewer/Designer
Error.razor /Error Fehlerseite

Grid-Komponenten

Beide Grid-Komponenten (CatalogsGrid.razor, MassDataGrid.razor) bieten:

Feature Beschreibung
DevExpress DxGrid Sortierung, Gruppierung, Filterung, Spalten-Resize, Spalten-Reorder
CRUD via Popup-EditForm Inline-Bearbeitung mit Validierung
Band-Columns Spalten können dynamisch in Bänder gruppiert werden
Layout-Persistierung Spaltenbreiten, Reihenfolge, Bänder, Grid-Layout werden pro User in der DB gespeichert
Size-Mode-Wechsel Klein/Mittel/Groß via Toolbar-Dropdown
Paginierung (MassData) Serverseitige Paginierung mit konfigurierbarer Seitengröße (100, 1.000, 10.000, 100.000, Alle)

Typisierte HTTP-Clients

Client API-Endpunkt Beschreibung
CatalogApiClient api/catalogs Vollständiges CRUD mit Fehlerbehandlung
MassDataApiClient api/massdata Paginiertes Laden, Upsert, Suche
DashboardApiClient api/dashboard/dashboards Dashboard-Liste laden
LayoutApiClient api/layouts Grid-Layouts laden/speichern/löschen

Alle Clients verwenden die IHttpClientFactory und werden via AddHttpClient<T>() registriert. Die ApiBaseUrl wird aus appsettings.json gelesen.

Fehlerbehandlung im Frontend

CatalogApiClient implementiert ein ApiResult<T> Pattern:

public record ApiResult<T>(bool Success, T? Value, string? Error);

HTTP-Fehler werden in benutzerfreundliche deutsche Meldungen übersetzt (z.B. 409 ? „Datensatz existiert bereits").

Theming

ThemeState verwaltet Light/Dark Mode mit DevExpress Fluent Theme:

var theme = Themes.Fluent.Clone(properties =>
{
    properties.Mode = isDarkMode ? ThemeMode.Dark : ThemeMode.Light;
    properties.ApplyToPageElements = true;
});
themeChangeService.SetTheme(theme);

Der Toggle-Button befindet sich im MainLayout.razor in der Top-Bar.


6. Abhängigkeiten zwischen Projekten

                    ????????????????????
                    ?  DbFirst.Domain  ?
                    ?  (keine Deps)    ?
                    ????????????????????
                             ?
                    ????????????????????
                    ? DbFirst.         ?
                    ? Application      ?
                    ? (? Domain)       ?
                    ????????????????????
                             ?
              ???????????????????????????????
              ?              ?              ?
    ????????????????  ??????????????       ?
    ? DbFirst.     ?  ? DbFirst.   ?       ?
    ? Infrastructure?  ? API        ?????????
    ? (? Domain,   ?  ? (? Domain, ?
    ?  Application)?  ? Application,?
    ????????????????  ? Infra)     ?
                      ??????????????

    ????????????????????
    ? DbFirst.         ?
    ? BlazorWebApp      ?
    ? (KEINE Projekt-  ?     HTTP
    ?  Referenzen)     ? ????????????  DbFirst.API
    ????????????????????

Wichtig: Das BlazorWebApp-Projekt hat bewusst keine Projekt-Referenz zu irgendeinem anderen Projekt. Es kommuniziert ausschließlich über HTTP mit der API. Dadurch können Frontend und Backend unabhängig deployed werden.


7. Database-First-Ansatz & Scaffold-Befehl

Philosophie

Die bestehende Produktionsdatenbank ist die Source of Truth. Es werden keine EF Core Migrations verwendet. Stattdessen wird der dotnet ef dbcontext scaffold Befehl verwendet, um Entities und DbContext aus der bestehenden Datenbank zu generieren.

Scaffold-Befehl (Allgemein)

dotnet ef dbcontext scaffold "<ConnectionString>" Microsoft.EntityFrameworkCore.SqlServer `
  --startup-project <StartupProjekt/Startup.csproj> `
  --project <Projektpfad/Projektname.csproj> `
  --context <DbContextName> `
  --context-dir <KontextOrdner> `
  --output-dir <EntitiesOrdner> `
  --table <Tabellenname> `
  --use-database-names `
  --no-onconfiguring `
  --force

Parameter-Erklärung

Parameter Beschreibung
--startup-project Das Startprojekt (muss die Microsoft.EntityFrameworkCore.Design-Tools enthalten) hier: DbFirst.API
--project Das Zielprojekt, in dem der DbContext generiert wird hier: DbFirst.Infrastructure
--context Name der generierten DbContext-Klasse
--context-dir Zielordner für den DbContext relativ zum --project
--output-dir Zielordner für die Entities relativ zum --project (hier: ../DbFirst.Domain/Entities ? Domain-Projekt!)
--table Optional: Nur bestimmte Tabelle(n) scaffolden, sonst alle
--use-database-names Spaltennamen exakt aus der DB übernehmen (kein PascalCase-Mapping)
--no-onconfiguring Kein Connection String in der OnConfiguring-Methode generieren (wir nutzen DI)
--force Bestehende Dateien überschreiben (ab dem 2. Scaffold-Lauf)

Konkretes Beispiel

dotnet ef dbcontext scaffold "Server=SDD-VMP04-SQL17\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;TrustServerCertificate=True;" Microsoft.EntityFrameworkCore.SqlServer `
  --startup-project DbFirst.API `
  --project DbFirst.Infrastructure `
  --context ApplicationDbContext `
  --context-dir . `
  --output-dir ../DbFirst.Domain/Entities `
  --table dbo.VWMY_CATALOG `
  --use-database-names `
  --no-onconfiguring `
  --force

Workflow nach dem Scaffold

  1. Scaffold ausführen ? Entities in DbFirst.Domain/Entities/, DbContext in DbFirst.Infrastructure/.
  2. DbContext anpassen: Konfigurierbare Spaltennamen über TableConfigurations einbauen, ggf. partial Methoden verwenden.
  3. Entity prüfen: Ggf. Properties umbenennen (PascalCase), das Mapping im DbContext entsprechend anpassen.
  4. Repository implementieren: In DbFirst.Infrastructure/Repositories/.
  5. MediatR Handler erstellen: In DbFirst.Application/.
  6. Controller erstellen: In DbFirst.API/Controllers/.

Hinweis zu --use-database-names

Dieser Parameter sorgt dafür, dass die DB-Spaltennamen (z.B. CAT_TITLE, ADDED_WHO) als Property-Namen in den Entities übernommen werden. In diesem Projekt wurden die Entities nach dem Scaffold manuell auf PascalCase umbenannt und das Mapping auf die Original-Spaltennamen erfolgt in der OnModelCreating-Methode des DbContext via .HasColumnName().


8. Datenbank-Architektur

Verwendete Datenbank-Objekte

Auf SQL17 (DefaultConnection)

Objekt-Typ Name Beschreibung
View VWMY_CATALOG Lese-View für Katalogeinträge
Stored Procedure PRTBMY_CATALOG_INSERT Neuen Katalog anlegen (Output: @GUID)
Stored Procedure PRTBMY_CATALOG_UPDATE Katalog aktualisieren (Titel bleibt, nur String + Audit)
Stored Procedure PRTBMY_CATALOG_SAVE Katalog speichern (Titel + String ändern erlaubt)
Stored Procedure PRTBMY_CATALOG_DELETE Katalog löschen
Tabelle TBDD_SMF_LAYOUT Grid-Layouts speichern (hat DB-Trigger: TBDD_SMF_LAYOUT_AFT_UPD)
Tabelle TBDD_SMF_CONFIG Dashboard-Konfigurationen (XML als VARBINARY)

Auf SQL19 (MassDataConnection)

Objekt-Typ Name Beschreibung
Tabelle MASSDATA Massendaten
Stored Procedure PRMassdata_UpsertByCustomerName Insert oder Update basierend auf CustomerName

Lese-/Schreib-Trennung

Lesen:   EF Core ? View/Tabelle (AsNoTracking)
Schreiben: EF Core ? ExecuteSqlRawAsync ? Stored Procedure
           ?
           Anschließend Reload des Datensatzes aus View/Tabelle

Grund: Die bestehende DB-Logik (Trigger, Berechnungen, Audit-Felder) in den Stored Procedures soll weiterhin greifen. EF Core wird primär als Lese-ORM verwendet.


9. CQRS-Pattern (MediatR)

Übersicht

Die Anwendung nutzt das CQRS-Pattern (Command Query Responsibility Segregation) über MediatR:

Controller ? MediatR.Send(Query/Command) ? Handler ? Repository ? DB

Alle Commands & Queries

Catalogs

Typ Klasse Request Response
Query GetAllCatalogsQuery List<CatalogReadDto>
Query GetCatalogByIdQuery int Id CatalogReadDto?
Command CreateCatalogCommand CatalogWriteDto CatalogReadDto?
Command UpdateCatalogCommand int Id, CatalogWriteDto CatalogReadDto?
Command DeleteCatalogCommand int Id bool

MassData

Typ Klasse Request Response
Query GetAllMassDataQuery int? Skip, int? Take List<MassDataReadDto>
Query GetMassDataCountQuery int
Query GetMassDataByCustomerNameQuery string CustomerName MassDataReadDto?
Command UpsertMassDataByCustomerNameCommand MassDataWriteDto MassDataReadDto

Datenfluss-Beispiel: Katalog anlegen

1. Blazor: Benutzer füllt Formular aus, klickt "Speichern"
2. CatalogsGrid.razor ? CatalogApiClient.CreateAsync(dto)
3. HTTP POST ? api/catalogs
4. CatalogsController.Create() ? _mediator.Send(new CreateCatalogCommand(dto))
5. CreateCatalogHandler:
   a. Prüft Duplikat via GetByTitleAsync()
   b. Mappt DTO ? Entity (AutoMapper)
   c. Ruft repository.InsertAsync() auf
6. CatalogRepository.InsertAsync():
   a. EXEC PRTBMY_CATALOG_INSERT mit Output-Parameter @GUID
   b. Lädt den Datensatz aus View: SELECT FROM VWMY_CATALOG WHERE GUID = @output
7. Response zurück durch die Schichten ? 201 Created
8. Blazor: Grid wird aktualisiert, neuer Eintrag fokussiert

10. API-Endpunkte

Catalogs (api/catalogs)

Methode Route Beschreibung Response
GET /api/catalogs Alle Kataloge laden 200 + List<CatalogReadDto>
GET /api/catalogs/{id} Katalog nach ID 200 / 404
POST /api/catalogs Neuen Katalog anlegen 201 / 409 (Duplikat)
PUT /api/catalogs/{id} Katalog aktualisieren 200 / 400 / 404
DELETE /api/catalogs/{id} Katalog löschen 204 / 404

Besonderheit PUT: Die UpdateProcedure im DTO steuert, ob PRTBMY_CATALOG_UPDATE (Titel unveränderbar) oder PRTBMY_CATALOG_SAVE (Titel änderbar) aufgerufen wird.

MassData (api/massdata)

Methode Route Beschreibung Response
GET /api/massdata/count Gesamtanzahl 200 + int
GET /api/massdata?skip=0&take=100 Paginiert laden 200 + List<MassDataReadDto>
GET /api/massdata/{customerName} Nach Kundenname suchen 200 / 404
POST /api/massdata/upsert Insert oder Update 200 + MassDataReadDto

Layouts (api/layouts)

Methode Route Beschreibung Response
GET /api/layouts?layoutType=...&layoutKey=...&userName=... Layout laden 200 / 404
POST /api/layouts Layout speichern/aktualisieren 200 + LayoutDto
DELETE /api/layouts?layoutType=...&layoutKey=...&userName=... Layout löschen 204 / 404

Dashboard (api/dashboard)

Route Beschreibung
api/dashboard/* DevExpress Dashboard Backend (automatisch gemappt via MapDashboardRoute)

SignalR Hub

Route Event Beschreibung
/hubs/dashboards DashboardsChanged Wird gefeuert, wenn ein Dashboard erstellt, geändert oder gelöscht wird

11. Blazor-Frontend & DevExpress

Komponentenhierarchie

App.razor
??? Routes.razor
    ??? MainLayout.razor                ? Sidebar + Content + Dark-Mode-Toggle
        ??? NavMenu.razor               ? Navigation
        ??? @Body
            ??? Home.razor              ? DxCarousel
            ??? Catalogs.razor
            ?   ??? CatalogsGrid.razor  ? DxGrid + Band-Editor
            ??? Massdata.razor
            ?   ??? MassDataGrid.razor  ? DxGrid + Band-Editor + Paginierung
            ??? Dashboard.razor         ? DxDashboard (Viewer/Designer)

Verwendete DevExpress Blazor Komponenten

Komponente Einsatzort Funktionen
DxGrid CatalogsGrid, MassDataGrid Daten anzeigen, sortieren, filtern, gruppieren, editieren
DxGridDataColumn Grid-Spalten Datenspalten
DxGridBandColumn Grid-Bänder Spalten-Gruppierung in Bänder
DxGridCommandColumn Grid-Aktionen Edit/Delete-Buttons
DxFormLayout Edit-Popups, Band-Editor Formular-Layout
DxTextBox Überall Text-Eingabe
DxComboBox Band-Zuweisung, Prozedur-Auswahl Dropdown
DxCheckBox MassData Edit Boolean-Eingabe
DxButton Überall Aktionen
DxDropDownButton Grid-Toolbar Size-Mode Auswahl
DxToolbar Grid-Toolbar Toolbar über dem Grid
DxPager MassDataGrid Seitennavigation
DxCarousel Home Bilder-Karussell
DxDashboard Dashboard Dashboard Viewer & Designer

DevExpress Grid-Features im Detail

Feature CatalogsGrid MassDataGrid
Sortierung ? ?
Gruppierung (Drag & Drop) ? ?
Spaltenfilter ? ?
Spalten-Resize ? ?
Spalten-Reorder ? ?
Popup-Bearbeitung ? ?
Inline-Validierung ? ?
Fokussierte Zeile ? ?
Band-Spalten (dynamisch) ? ?
Layout-Persistierung ? ?
Size-Mode Toggle ? ?
Serverseitige Paginierung ? ?
Pager-Komponente ? ?
Löschfunktion ? ? (deaktiviert)

12. Dashboard-System (DevExpress Dashboards)

Architektur

Blazor (DxDashboard)  ??HTTP???  API (DefaultDashboardController)
                                        ?
                                  DashboardConfigurator
                                        ?
                                  ??????????????
                                  ?             ?
                          SqlDashboard    DataSource
                          Storage         InMemoryStorage
                             ?                 ?
                        SQL Tabelle       JSON APIs
                      (TBDD_SMF_CONFIG)   (api/catalogs)

Features

  • Viewer-Modus: Dashboard anzeigen (read-only).
  • Designer-Modus: Dashboard interaktiv bearbeiten (Datenquellen, Charts, Grids etc.).
  • Persistierung: Dashboards werden als XML in der SQL-Tabelle TBDD_SMF_CONFIG gespeichert.
  • Auto-Seed: Beim Start werden Default-Dashboards erstellt, wenn sie fehlen.
  • Echtzeit-Sync: Dashboard-Änderungen werden via SignalR an alle verbundenen Clients gepusht.
  • Navigation: Sidebar zeigt alle verfügbaren Dashboards. URL-basierte Navigation mit optionalem Mode-Parameter (?mode=designer / ?mode=viewer).

Dashboard-Datenquellen

Name Typ Quelle
Catalogs (API) DashboardJsonDataSource {ApiBaseUrl}/api/catalogs
JSON Data Source (URL) DashboardJsonDataSource Externe URL (DevExpress-Beispieldaten)

13. Layout-Persistierung

Konzept

Benutzer können das Grid-Layout (Spaltenbreiten, Reihenfolge, Bänder, Gruppierung, Sortierung, Filterzustände, Size-Mode) pro Grid und pro User speichern.

Datenfluss

1. User ändert Grid-Layout (Spalten verschieben, Bänder definieren, etc.)
2. User klickt "Layout speichern"
3. CatalogsGrid/MassDataGrid ? BandLayoutService.SaveBandLayoutAsync()
4. BandLayoutService serialisiert BandLayout als JSON
5. LayoutApiClient.UpsertAsync() ? HTTP POST api/layouts
6. LayoutsController ? LayoutRepository.UpsertAsync()
7. EF Core ? INSERT/UPDATE in TBDD_SMF_LAYOUT

User-Identifikation

Da noch keine Authentifizierung implementiert ist, wird pro Browser ein zufälliger User-Key im localStorage generiert:

var layoutUser = await jsRuntime.InvokeAsync<string?>("localStorage.getItem", LayoutUserStorageKey);
if (string.IsNullOrWhiteSpace(layoutUser))
{
    layoutUser = Guid.NewGuid().ToString("N");
    await jsRuntime.InvokeVoidAsync("localStorage.setItem", LayoutUserStorageKey, layoutUser);
}

BandLayout-Modell

public class BandLayout
{
    public List<BandDefinition> Bands { get; set; }        // Definierte Bänder
    public List<string> ColumnOrder { get; set; }           // Spaltenreihenfolge
    public Dictionary<string, string?> ColumnWidths { get; set; } // Spaltenbreiten
    public GridPersistentLayout? GridLayout { get; set; }   // DevExpress Grid-State
    public SizeMode SizeMode { get; set; }                  // Klein/Mittel/Groß
}

Speicherort in DB

Spalte Inhalt
LAYOUT_TYPE "GRID_BANDS"
LAYOUT_KEY "CatalogsGrid" oder "MassDataGrid"
USER_NAME Generierter User-Key
LAYOUT_DATA JSON (UTF-8 Bytes)

14. Echtzeit-Kommunikation (SignalR)

Verwendung

SignalR wird an zwei Stellen eingesetzt:

Stelle Zweck
Blazor-intern Blazor Server nutzt SignalR automatisch für die UI-Synchronisation (kein eigenes Setup nötig)
Dashboard-Updates Eigener SignalR Hub (/hubs/dashboards) für Dashboard-Änderungs-Benachrichtigungen

Dashboard SignalR Flow

1. User A ändert Dashboard im Designer ? SaveDashboard()
2. SqlDashboardStorage.SaveDashboard() speichert in DB
3. SqlDashboardStorage ruft _notifier.NotifyChanged() auf
4. DashboardChangeNotifier sendet "DashboardsChanged" via HubContext
5. Alle verbundenen Clients (User B, C, ...) empfangen das Event
6. Dashboard.razor empfängt Event ? RefreshDashboards()
7. Dashboard-Liste wird aktualisiert (ohne Page Reload)

15. Konfiguration

DbFirst.API appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=...;Database=DD_ECM;...",     // SQL17 (Catalogs, Layouts, Dashboards)
    "MassDataConnection": "Server=...;Database=DD_ECM;..."     // SQL19 (MassData)
  },
  "Dashboard": {
    "BaseUrl": "https://localhost:7204"                         // API-URL für Dashboard-Datenquellen
  },
  "Cors": {
    "AllowedOrigins": ["https://localhost:7276", "http://localhost:5101"]
  },
  "TableConfigurations": {
    "VwmyCatalog": {
      "ViewName": "VWMY_CATALOG",
      "GuidColumnName": "GUID",
      ...
    }
  }
}

DbFirst.BlazorWebApp appsettings.json

{
  "ApiBaseUrl": "https://localhost:7204/"    // Backend-API-Adresse
}

URLs (Entwicklungsumgebung)

Anwendung HTTPS HTTP
DbFirst.API https://localhost:7204 http://localhost:5131
DbFirst.BlazorWebApp https://localhost:7191 http://localhost:5096

16. Lokale Entwicklungsumgebung

Voraussetzungen

Software Version
.NET SDK 8.0+
Visual Studio 2022 (17.8+) empfohlen
SQL Server Zugang zu den konfigurierten Instanzen (SQL17, SQL19)
DevExpress Blazor Lizenz 25.2.3 (NuGet-Feed konfiguriert)

Projekt starten

Beide Projekte müssen gleichzeitig gestartet werden (Multi-Startup in Visual Studio):

  1. Rechtsklick auf die Solution ? „Startprojekte konfigurieren"
  2. DbFirst.API ? Starten
  3. DbFirst.BlazorWebApp ? Starten
  4. F5 drücken

Alternativ in zwei Terminals:

# Terminal 1: API
cd DbFirst.API
dotnet run --launch-profile https

# Terminal 2: Blazor
cd DbFirst.BlazorWebApp
dotnet run --launch-profile https

Swagger UI

Die API-Dokumentation ist im Development-Modus unter https://localhost:7204/swagger erreichbar.

Neue Tabelle/View hinzufügen (Workflow)

  1. Scaffold der neuen Tabelle/View:
    dotnet ef dbcontext scaffold "..." Microsoft.EntityFrameworkCore.SqlServer `
      --startup-project DbFirst.API `
      --project DbFirst.Infrastructure `
      --context ApplicationDbContext `
      --context-dir . `
      --output-dir ../DbFirst.Domain/Entities `
      --table dbo.NEUE_TABELLE `
      --use-database-names `
      --no-onconfiguring `
      --force
    
  2. Entity überprüfen/anpassen in DbFirst.Domain/Entities/
  3. DbContext überprüfen ggf. OnModelCreating anpassen
  4. Repository-Interface erstellen in DbFirst.Application/Repositories/
  5. Repository-Implementierung erstellen in DbFirst.Infrastructure/Repositories/
  6. DTOs erstellen in DbFirst.Application/<Feature>/
  7. AutoMapper Profile erstellen
  8. MediatR Commands/Queries + Handler erstellen
  9. Controller erstellen in DbFirst.API/Controllers/
  10. DI registrieren in Program.cs
  11. Frontend-DTOs spiegeln in DbFirst.BlazorWebApp/Models/
  12. ApiClient erstellen in DbFirst.BlazorWebApp/Services/
  13. Blazor-Komponente erstellen

17. Architektur-Entscheidungen (ADRs)

ADR-001: Database-First statt Code-First

Kontext: Die Datenbank existiert bereits in Produktion mit komplexer Logik in SPs und Triggern.
Entscheidung: Database-First via dotnet ef dbcontext scaffold.
Begründung: Keine Migrationen nötig, bestehende DB-Logik bleibt intakt, kein Risiko durch Code-First-Migrationen auf Prod-DB.

ADR-002: Stored Procedures für Schreiboperationen

Kontext: Die bestehende DB nutzt SPs für Insert/Update/Delete mit spezieller Logik (Audit, Output-Parameter, Trigger).
Entscheidung: EF Core ExecuteSqlRawAsync für SP-Aufrufe, EF Core nur für Leseoperationen.
Begründung: Bestehende Business-Logik in SPs wird beibehalten. EF Core wird nicht als vollständiges CRUD-ORM genutzt, sondern primär als Lese-Mapper.

ADR-003: Kein generisches Repository für alle Entities

Kontext: Es existiert ein IRepository<T>, aber nicht alle Repositories implementieren es.
Entscheidung: Spezialisierte Repository-Interfaces pro Feature.
Begründung: Die Operationen sind zu asymmetrisch (SP-basierte CRUD vs. EF Core CRUD, Composite Keys vs. int-ID, Upsert statt Insert+Update). Ein erzwungenes generisches Pattern würde zu viel Komplexität erzeugen (siehe Kommentar im Code von CatalogRepository).

ADR-004: Zwei separate DbContexts

Kontext: Entities liegen auf verschiedenen SQL-Server-Instanzen.
Entscheidung: ApplicationDbContext (SQL17) und MassDataDbContext (SQL19).
Begründung: Unterschiedliche Connection Strings erfordern separate DbContexts.

ADR-005: Blazor ohne Projekt-Referenz zum Backend

Kontext: Frontend soll unabhängig vom Backend sein.
Entscheidung: BlazorWebApp hat keine Projekt-Referenz zu Domain/Application/Infrastructure. Eigene DTOs im Frontend.
Begründung: Saubere Trennung, Frontend und Backend können unabhängig deployed werden. DTO-Duplikation ist bewusst in Kauf genommen.

ADR-006: MediatR für CQRS

Kontext: Klare Trennung von Lese- und Schreiboperationen gewünscht.
Entscheidung: MediatR mit expliziten Command- und Query-Records.
Begründung: Jeder Use Case hat seinen eigenen Handler gut testbar, erweiterbar (Pipeline Behaviors für Logging, Validation etc.).

ADR-007: Layout-Persistierung in DB statt im Browser

Kontext: Grid-Layouts sollen über Sessions und Geräte hinweg erhalten bleiben.
Entscheidung: Layouts als JSON in DB-Tabelle TBDD_SMF_LAYOUT speichern.
Begründung: localStorage wäre browserspezifisch. DB-Persistierung ermöglicht geräteübergreifende Layouts.


18. Erweiterbarkeit & nächste Schritte

Offene TODOs (aus dem Code)

Stelle TODO
Program.cs (API) CORS-Origins aus appsettings konfigurierbar machen für Produktion
CatalogRepository.cs Prüfung ob generisches Repository sinnvoll (Fazit: nein, bewusst entschieden)
MassDataGrid Löschfunktion noch nicht implementiert

Empfohlene nächste Schritte

# Thema Beschreibung
1 Authentifizierung Azure AD / Windows Auth einführen den generierten Layout-User-Key durch echte Benutzeridentität ersetzen
2 Validierung FluentValidation in die MediatR Pipeline einbauen (Pipeline Behavior)
3 Logging Strukturiertes Logging mit Serilog, ggf. MediatR Logging-Behavior
4 Unit Tests Test-Projekt für Handler, Repositories (mit InMemory-DB oder Mocks)
5 CI/CD Pipeline für Build, Test, Deployment
6 Error Handling Result-Pattern (Result<T>) statt null-Returns in Handlern
7 Caching Response-Caching oder In-Memory-Cache für häufige Leseanfragen
8 Shared DTOs Ggf. gemeinsames DTO-Projekt für Frontend und Backend, um Duplikation zu reduzieren

19. Glossar

Begriff Bedeutung
Clean Architecture Architekturstil mit konzentrischen Schichten, bei dem Abhängigkeiten nur nach innen zeigen
CQRS Command Query Responsibility Segregation Trennung von Lese- und Schreiboperationen
Database-First EF Core generiert Code aus bestehender Datenbank (Gegenteil: Code-First)
DDD Domain-Driven Design Domäne steht im Zentrum der Architektur
DTO Data Transfer Object Objekt für den Datentransport zwischen Schichten
Entity Domänenobjekt, das einer DB-Tabelle/View entspricht
MediatR .NET-Library für das Mediator-Pattern (in-process Messaging)
Scaffold Automatische Code-Generierung aus bestehender DB-Struktur
SP (Stored Procedure) Gespeicherte SQL-Prozedur in der Datenbank
Upsert Insert + Update in einer Operation
Band-Column DevExpress Grid-Feature: Spalten unter einer gemeinsamen Überschrift gruppieren
Interactive Server Rendering Blazor Render-Modus, bei dem der UI-State auf dem Server lebt