Files
ECMJobRunner/ECMJobRunner.Infrastructure/AGENTS.md
TekH 7d53b599de Add Infrastructure layer with EF6/EF Core support
Introduced a robust Infrastructure layer for the ECMJobRunner system:
- Added `AGENTS.md` with detailed project documentation.
- Implemented generic repository and unit-of-work patterns.
- Added `CfgProfileRepository`, `ProfileSqlJobRepository`, and `ProfileHistoryRepository`.
- Integrated AutoMapper for DTO-to-entity mapping.
- Added multi-framework support for .NET Framework 4.8 (EF6) and .NET 8.0 (EF Core) using conditional compilation.
- Updated `ECMJobRunner.Infrastructure.csproj` with metadata fixes and dependencies.
- Introduced dependency injection extension for .NET 8.0.
- Enhanced project structure and database context with entity mappings.
2026-07-09 13:35:02 +02:00

6.2 KiB

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:

  • Profiledbo.TBJR_CFG_PROFILE
  • ProfileSqlJobdbo.TBJR_CFG_PROFILE_SQLJOB
  • ProfileHistorydbo.TBJR_OUT_PROFILE_HISTORY

Column Mappings: (Examples)

  • Profile.ProfileNamePROFILE_NAME
  • ProfileSqlJob.SqlCheckQuerySQL_CHECK_QUERY
  • All navigation properties configured with relationships

Repository Implementations

Repository

Generic repository implementing IRepository<TEntity> with full CRUD operations.

Key Methods:

  • Synchronous: GetById, GetAll, Find, SingleOrDefault, Add, Update, Remove
  • Asynchronous: GetByIdAsync, GetAllAsync, FindAsync, SingleOrDefaultAsync

Entity-Specific Repositories

  • ProfileRepository : Repository<Profile>, IProfileRepository
  • ProfileSqlJobRepository : Repository<ProfileSqlJob>, IProfileSqlJobRepository
  • ProfileHistoryRepository : Repository<ProfileHistory>, 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):

#if NET48
using System.Data.Entity;
public class JobRunnerDbContext : DbContext
#endif

EF Core (.NET 8.0):

#if !NET48
using Microsoft.EntityFrameworkCore;
public class JobRunnerDbContext : DbContext
#endif

Building the Project

dotnet build ECMJobRunner.Infrastructure.csproj

For specific framework:

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<T>

Configuration

  • EF6: DbModelBuilder in OnModelCreating
  • EF Core: ModelBuilder in OnModelCreating

Querying

  • EF6: DbSet<T>.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<T>? 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

// 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();
  • 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