# ECMJobRunner.Infrastructure ## Project Overview ECMJobRunner.Infrastructure is the **infrastructure layer** for the ECM Job Runner system following **Clean Architecture** principles. This project contains: - **DbContext implementation** with Entity Framework - **Repository implementations** for data access - **Entity configurations** (EF mappings) - **Database connection management** **Key Principle**: This layer implements the interfaces defined in the Domain layer and handles all database concerns. ## Target Frameworks - **.NET Framework 4.8** (`net480`) - Uses **Entity Framework 6.5.1** - **.NET 8.0** (`net8.0`) - Uses **Entity Framework Core 8.0.11** The project uses conditional compilation to support both EF6 and EF Core with the same codebase. ## Architecture This project follows **Clean Architecture** principles: - **Depends on Domain layer** (implements domain interfaces) - **No dependencies from Domain** (dependency inversion) - **Conditional compilation** for EF6 vs EF Core differences - **Repository pattern** implementation - **Unit of Work pattern** implementation ## Project Structure ``` ECMJobRunner.Infrastructure/ ├── Data/ │ └── JobRunnerDbContext.cs # DbContext with conditional compilation ├── Repositories/ │ ├── Repository.cs # Generic repository implementation │ ├── ProfileRepository.cs # Profile-specific repository │ ├── ProfileSqlJobRepository.cs │ ├── ProfileHistoryRepository.cs │ └── UnitOfWork.cs # Unit of Work implementation ├── ECMJobRunner.Infrastructure.csproj └── AGENTS.md # This file ``` ## Database Context ### JobRunnerDbContext Multi-targeted DbContext supporting both EF6 and EF Core: **DbSets:** - `Profiles`: DbSet - `ProfileSqlJobs`: DbSet - `ProfileHistories`: DbSet **Configuration:** - Connection string via constructor parameter - Conditional compilation directives (`#if NET48` / `#else`) - Fluent API configurations in `OnModelCreating` **Table Mappings:** - `Profile` → `dbo.TBJR_CFG_PROFILE` - `ProfileSqlJob` → `dbo.TBJR_CFG_PROFILE_SQLJOB` - `ProfileHistory` → `dbo.TBJR_OUT_PROFILE_HISTORY` **Column Mappings:** (Examples) - `Profile.ProfileName` → `PROFILE_NAME` - `ProfileSqlJob.SqlCheckQuery` → `SQL_CHECK_QUERY` - All navigation properties configured with relationships ## Repository Implementations ### Repository Generic repository implementing `IRepository` with full CRUD operations. **Key Methods:** - Synchronous: `GetById`, `GetAll`, `Find`, `SingleOrDefault`, `Add`, `Update`, `Remove` - Asynchronous: `GetByIdAsync`, `GetAllAsync`, `FindAsync`, `SingleOrDefaultAsync` ### Entity-Specific Repositories - `ProfileRepository : Repository, IProfileRepository` - `ProfileSqlJobRepository : Repository, IProfileSqlJobRepository` - `ProfileHistoryRepository : Repository, IProfileHistoryRepository` These can be extended with entity-specific query methods as needed. ### UnitOfWork Implements `IUnitOfWork` interface: - Manages DbContext lifecycle - Provides repository instances - Handles transaction management via `SaveChanges`/`SaveChangesAsync` ## Connection String Default connection string (configured in consuming applications): ``` Server=SDD-VMP04-SQL17\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True; ``` ## Database Schema Source SQL scripts and schema definitions are located at: ``` M:\Datenbank\[DD_ECM]-Database\JobRunner\ ``` ## Dependencies ### .NET Framework 4.8 (`net480`) - **ECMJobRunner.Domain** (project reference) - **EntityFramework 6.5.1** (NuGet package) ### .NET 8.0 (`net8.0`) - **ECMJobRunner.Domain** (project reference) - **Microsoft.EntityFrameworkCore 8.0.11** (NuGet package) - **Microsoft.EntityFrameworkCore.SqlServer 8.0.11** (NuGet package) ## Conditional Compilation The project uses `#if NET48` / `#else` directives to handle differences between EF6 and EF Core: **EF6 (.NET Framework 4.8):** ```csharp #if NET48 using System.Data.Entity; public class JobRunnerDbContext : DbContext #endif ``` **EF Core (.NET 8.0):** ```csharp #if !NET48 using Microsoft.EntityFrameworkCore; public class JobRunnerDbContext : DbContext #endif ``` ## Building the Project ```bash dotnet build ECMJobRunner.Infrastructure.csproj ``` For specific framework: ```bash dotnet build ECMJobRunner.Infrastructure.csproj -f net8.0 dotnet build ECMJobRunner.Infrastructure.csproj -f net480 ``` ## Entity Framework Differences ### DbContext Constructor - **EF6**: Accepts connection string directly - **EF Core**: Requires `DbContextOptions` ### Configuration - **EF6**: `DbModelBuilder` in `OnModelCreating` - **EF Core**: `ModelBuilder` in `OnModelCreating` ### Querying - **EF6**: `DbSet.AsNoTracking()` extension - **EF Core**: Same API, built-in support ### Async Operations - **EF6**: Limited async support - **EF Core**: Full async/await support ## Development Notes - **Nullable navigation properties**: `IEnumerable?` to support defensive programming - **No lazy loading**: Navigation properties loaded explicitly via `.Include()` - **Transaction management**: Handled by Unit of Work pattern - **Repository pattern**: Encapsulates EF-specific code - **Clean Architecture**: Infrastructure depends on Domain, not vice versa ## Usage Example ```csharp // Create DbContext (connection string from configuration) var connectionString = ConfigurationManager.ConnectionStrings["JobRunner"].ConnectionString; var context = new JobRunnerDbContext(connectionString); // Use Unit of Work using var unitOfWork = new UnitOfWork(context); // Query profiles var activeProfiles = await unitOfWork.Profiles .FindAsync(p => p.Active); // Add new profile var profile = new Profile { ProfileName = "Test", Active = true }; unitOfWork.Profiles.Add(profile); await unitOfWork.SaveChangesAsync(); ``` ## Related Projects - **ECMJobRunner.Domain**: Contains entities and repository interfaces - **ECMJobRunner.Application**: Application layer consuming repositories ## Company Information **Author**: Digital Data GmbH **Copyright**: 2026 **Repository**: http://git.dd:3000/AppStd/ECMJobRunner.git