CleanArchAcceleratorTools.Infrastructure 1.0.1

dotnet add package CleanArchAcceleratorTools.Infrastructure --version 1.0.1
                    
NuGet\Install-Package CleanArchAcceleratorTools.Infrastructure -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CleanArchAcceleratorTools.Infrastructure" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CleanArchAcceleratorTools.Infrastructure" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="CleanArchAcceleratorTools.Infrastructure" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CleanArchAcceleratorTools.Infrastructure --version 1.0.1
                    
#r "nuget: CleanArchAcceleratorTools.Infrastructure, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CleanArchAcceleratorTools.Infrastructure@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CleanArchAcceleratorTools.Infrastructure&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=CleanArchAcceleratorTools.Infrastructure&version=1.0.1
                    
Install as a Cake Tool

CleanArchAcceleratorTools.Infrastructure

This module is part of CleanArchAcceleratorTools, a toolkit to accelerate building applications with Clean Architecture. It implements the Infrastructure layer.

Related modules:

📄 License: MIT


🧠 Principles

🔗 Role in the architecture

  • Controller: Exposes endpoints, it does not contain business rules.
  • Application: Orchestrates use cases and references the Domain and repository.
  • Domain: Pure domain with business rules and validations.
  • Infrastructure: Implements persistence/mapping for Domain entities.
  • Mediator: Handles commands, queries, and notifications.

✨ Features

  • Dynamic Selects – Project typed objects based on property names.
  • Dynamic Filtering – Filter queries with a fluent builder using clauses and operators.
  • Dynamic Sort – Sort queries with multiple fields and directions.
  • Pagination Utilities – Helpers for IQueryable including filtering and ordering.
  • Parallel Query Execution – Process large query sets in parallel.
  • Simplified Entity Mapping – Configure and register mappings for domain models.
  • Generic Repository – Reusable repository pattern for CRUD and advanced queries.
  • DataTable Creation – Build DataTable from lists for procedures and raw SQL.
  • Extensible & Lightweight – Modular, discoverable, and easy to integrate.

🧩 Compatibility

Multi-target:

  • .NET 6
  • .NET 7
  • .NET 8
  • .NET 9

Use an EF Core version compatible with your target framework.


✅ Prerequisites

  • EF Core 6+ (match your framework)
  • A configured DbContext
  • Optional: Newtonsoft.Json or System.Text.Json for serialization scenarios

🚀 Installation

dotnet add package CleanArchAcceleratorTools.Infrastructure --version 1.0.0

⚡ Quickstart

  1. If you have separated Application project add this module reference on it. Add allInOne if using a single project.
  2. Register your DbContext in DI.
    builder.Services.AddDbContext<YourContext>();
    builder.Services.AddDbContextFactory<YourContext, YourContextFactory>();
    
  3. Configure the generic DbContext DI and CleaArch services
    builder.Services.AddScoped<DbContext>(sp => sp.GetRequiredService<YourContext>());
    builder.Services.AddScoped<IDbContextFactory<DbContext>>(sp => new DbContextFactoryAdapter(sp.GetRequiredService<IDbContextFactory<YourContext>>()));
    
    builder.Services.AddCleanArchConfiguration<YourContext>();
    
  4. Create your models as needed. Needed to Inherit from a base Entity if you want to use common properties.
  5. (Optional) Map your entities using EntityTypeConfiguration<T> as the usage example below.
  6. (Optional) Create your repositories extending IGenericRepository<T> and GenericRepository<T> as example below.
  7. Use the features provided.

🛠️ Usage Examples

Dynamic Select

Tired of Include and ThenInclude everything? With DynamicSelect, you can easily project only the properties you need, without the overhead of loading entire entities and without having to make the Select manually each time. You can simply add the fields you want for each relationship and the library will handle the rest. It supports simple properties and nested complex relationships, including Collections.

It includes filtering and ordering capabilities too.

Bonus Tip: Enable NullValueHandling = NullValueHandling.Ignore in Newtonsoft.Json serialization or similars to have a GraphQL like solution for your REST APIs.

You can select simple properties of the entity

var courses = await _yourContext.Courses
    .DynamicSelect(nameof(Course.Id), nameof(Course.Title))
    .ToListAsync();
Or you can select complex properties, including collections
string[] AllRelationships =
[
    string.Format("{0}", nameof(Course.Id)),
    string.Format("{0}", nameof(Course.InstructorId)),
    string.Format("{0}", nameof(Course.Title)),
    string.Format("{0}", nameof(Course.CreatedAt)),
    string.Format("{0}.{1}", nameof(Course.Instructor), nameof(Course.Instructor.Id)),
    string.Format("{0}.{1}", nameof(Course.Instructor), nameof(Course.Instructor.FullName)),
    string.Format("{0}.{1}", nameof(Course.Instructor), nameof(Course.Instructor.CreatedAt)),
    string.Format("{0}.{1}.{2}", nameof(Course.Instructor), nameof(Instructor.Profile), nameof(Profile.Id)),
    string.Format("{0}.{1}.{2}", nameof(Course.Instructor), nameof(Instructor.Profile), nameof(Profile.InstructorId)),
    string.Format("{0}.{1}.{2}", nameof(Course.Instructor), nameof(Instructor.Profile), nameof(Profile.Bio)),
    string.Format("{0}.{1}.{2}", nameof(Course.Instructor), nameof(Instructor.Profile), nameof(Profile.LinkedInUrl)),
    string.Format("{0}.{1}.{2}", nameof(Course.Instructor), nameof(Instructor.Profile), nameof(Profile.CreatedAt)),
    string.Format("{0}.{1}", nameof(Course.Modules), nameof(Module.Id)),
    string.Format("{0}.{1}", nameof(Course.Modules), nameof(Module.CourseId)),
    string.Format("{0}.{1}", nameof(Course.Modules), nameof(Module.Name)),
    string.Format("{0}.{1}", nameof(Course.Modules), nameof(Module.CreatedAt)),
    string.Format("{0}.{1}.{2}", nameof(Course.Modules), nameof(Module.Lessons), nameof(Lesson.Id)),
    string.Format("{0}.{1}.{2}", nameof(Course.Modules), nameof(Module.Lessons), nameof(Lesson.ModuleId)),
    string.Format("{0}.{1}.{2}", nameof(Course.Modules), nameof(Module.Lessons), nameof(Lesson.Title)),
    string.Format("{0}.{1}.{2}", nameof(Course.Modules), nameof(Module.Lessons), nameof(Lesson.Duration)),
    string.Format("{0}.{1}.{2}", nameof(Course.Modules), nameof(Module.Lessons), nameof(Lesson.CreatedAt))
];

var courses = await _yourContext.Courses
    .DynamicSelect(AllRelationships)
    .ToListAsync();
You can filter and sort as well
var dynamicFilter = ...;
var dynamicSort = ...;

// populate dynamicFilter and dynamicSort with Set properties or Builder...

var courses = await _yourContext.Courses            
    .DynamicSelect(nameof(Course.Id), nameof(Course.Title))
    .Where(dynamicFilter.CompileFilter())
    .OrderBy(dynamicSort.CompileSort().First().Expression)
    .ToListAsync();

Pagination

Effortlessly paginate your queries, with dynamic filtering and dynamic ordering capabilities:

var dynamicFilter = ...;
var dynamicSort = ...;

// populate dynamicFilter and dynamicSort with Set properties or Builder...

var queryFilter = new QueryFilterBuilder<Course>()
    .WithPage(1)
    .WithPageSize(100)
    .WithDynamicFilter(dynamicFilter)
    .WithDynamicSort(dynamicSort)
    .WithFields(SelectsDefaults<Course>.BasicFields)
    .Build();

var firstPage = await _yourContext.Courses
    .OrderBy(x => x.Id)
    .GetPagination(queryFilter)
    .ToPaginationResultListAsync();

Entity Mapping

Map your entities with ease:

public class CourseMap : EntityTypeConfiguration<Course>
{
    public override void Map(EntityTypeBuilder<Course> builder)
    {
        builder.ToTable("TB_COURSE");

        builder.HasKey(x => x.Id)
               .HasName("SQ_COURSE");

        builder.Property(x => x.Id)
               .HasColumnName("SQ_COURSE")
               .HasColumnType("bigint")
               .UseIdentityColumn();

        builder.Property(x => x.InstructorId)
               .HasColumnName("SQ_INSTRUCTOR")
               .HasColumnType("bigint");

        builder.Property(x => x.Title)
               .HasColumnName("TX_TITLE")
               .HasColumnType("nvarchar(100)");

        builder.Property(x => x.CreatedAt)
               .HasColumnName("DT_CREATION")
               .HasColumnType("nvarchar(100)");
    }
}

...

public static class MappingsHolder
{
    public static Dictionary<Type, IEntityTypeConfiguration> GetMappings()
    {
        var mappings = new Dictionary<Type, IEntityTypeConfiguration>();

        mappings.Add(typeof(Course), new CourseMap());

        return mappings;
    }
}

...

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    modelBuilder.RegisterModelsMapping(MappingsHolder.GetMappings());
}

Parallel Query Execution

Execute queries in parallel to improve performance on large datasets:

await ParallelQueryExecutor.DoItParallelAsync
(
    () => _registeredContextFactory.Create(Guid.NewGuid().ToString()).Courses.OrderBy(x => x.Id).AsQueryable(),
    new ParallelParams
    {
        TotalRegisters = _yourContext.Courses.Count(),
        BatchSize = 10,
        MaximumDegreeOfParalelism = Environment.ProcessorCount,
        MaxDegreeOfProcessesPerThread = 1
    },
    _logger
);

Generic Repository

Leverage a robust, reusable repository for your entities:

public interface ICourseRepository : IGenericRepository<Course> { }

public class CourseRepository : GenericRepository<Course>, ICourseRepository
{
    private readonly YourContext _yourContext;
    private readonly IDbContextRegistratorService<YourContext> _registeredContextFactory;
    private readonly IApplicationLogger _logger;

    public CourseRepository(
        YourContext context,
        IDbContextRegistratorService<YourContext> registeredContextFactory,
        IApplicationLogger logger
    ) : base(context, new DbContextRegistratorServiceAdapter(registeredContextFactory))
    {
        _yourContext = context;
        _registeredContextFactory = registeredContextFactory;
        _logger = logger;
    }
}

...

// Usage
var allCourses = await _courseRepository.GetAllAsync();

DataTable Creation

Easily create DataTables, from Lists, for use in stored procedures and raw SQL queries:

var columnsOrder = new Dictionary<string, int>()
{
    { "Id", 0 },
    { "InstructorId", 1 },
    { "Title", 2 }
};
var courses = await _courseRepository.GetAllAsync();
var dataTable = courses.ToDataTable(columnsOrder, context);
Obs: The list type must be mapped in the context!

📚 Example Project

See the - CleanArchAcceleratorTools.Examples project for a complete working example, including setup and advanced scenarios. It implements a fully working API with all other modules implemented.


🧠 Tips

  • Prefer DynamicSelect to reduce materialization and network payloads.
  • Tune ParallelParams (BatchSize, MaximumDegreeOfParalelism) per environment and workload.
  • Keep entity maps consistent and centralized via MappingsHolder for discoverability.
  • Centralize selection fields in a constant for reuse as in CourseSelects.

🤝 Contributing

Contributions are welcome! Open issues or submit PRs for features, bug fixes, or documentation improvements. Contributing guidelines are under construction.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on CleanArchAcceleratorTools.Infrastructure:

Package Downloads
CleanArchAcceleratorTools.Application

This module is part of CleanArchAcceleratorTools, a toolkit to accelerate building applications with Clean Architecture.

CleanArchAcceleratorTools.AllInOne

This module is part of CleanArchAcceleratorTools, a toolkit to accelerate building applications with Clean Architecture.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 378 12/17/2025
1.0.0 360 12/17/2025