Skip to content

Replace AutoMapper with Mapperly and update DI#5

Merged
yilmaztayfun merged 1 commit into
masterfrom
f/aether-upgrade
Mar 22, 2026
Merged

Replace AutoMapper with Mapperly and update DI#5
yilmaztayfun merged 1 commit into
masterfrom
f/aether-upgrade

Conversation

@yilmaztayfun
Copy link
Copy Markdown
Contributor

@yilmaztayfun yilmaztayfun commented Mar 22, 2026

Migrate mapping implementation from AutoMapper to Mapperly (BBT.Aether.Mapperly): add Mapperly package, replace map profiles with Riok.Mapperly-style partial mappers and [Mapper] annotations, and register generated mappers in DI. Update host and test startup to call AddAetherMapperlyMapper instead of the AutoMapper variant. Bump Aether package version in Directory.Build.props and remove the AutoMapper package entry. Misc: make GitRepository ORM ctor public and add solution configurations (x64/x86) to the .sln.

Summary by Sourcery

Migrate the application template from AutoMapper to Mapperly-based mapping and align dependency injection, domain model, and configuration accordingly.

New Features:

  • Introduce Mapperly-based mapper classes for GitRepository and Issue entities, including input and list mappers.

Enhancements:

  • Register Mapperly-generated mappers in the application dependency injection container.
  • Expose the GitRepository parameterless constructor publicly to support ORM usage.
  • Switch API host and infrastructure test startup to use AddAetherMapperlyMapper instead of the AutoMapper-based registration.
  • Update shared build configuration and project references to use the newer Aether Mapperly package and remove the AutoMapper dependency.

Build:

  • Adjust Directory.Build.props and related project files to reference the updated Aether package and drop AutoMapper.

Chores:

  • Add x64/x86 solution platform configurations to the solution file.

Summary by CodeRabbit

Release Notes

  • Chores

    • Updated package version to 1.0.20
    • Added x64 and x86 platform build configurations
  • Refactor

    • Updated mapping library integration and dependencies
  • Bug Fixes

    • Improved framework compatibility for entity instantiation

Migrate mapping implementation from AutoMapper to Mapperly (BBT.Aether.Mapperly): add Mapperly package, replace map profiles with Riok.Mapperly-style partial mappers and [Mapper] annotations, and register generated mappers in DI. Update host and test startup to call AddAetherMapperlyMapper instead of the AutoMapper variant. Bump Aether package version in Directory.Build.props and remove the AutoMapper package entry. Misc: make GitRepository ORM ctor public and add solution configurations (x64/x86) to the .sln.
@yilmaztayfun yilmaztayfun self-assigned this Mar 22, 2026
@yilmaztayfun yilmaztayfun requested review from a team and middt March 22, 2026 20:24
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Mar 22, 2026

Reviewer's Guide

Replaces AutoMapper-based profiles with Mapperly partial mapper classes integrated via BBT.Aether.Mapperly, wires the new mappers into DI and host/test startup, adjusts GitRepository’s ORM constructor visibility, updates solution configurations, and bumps Aether-related package references while removing AutoMapper dependencies.

File-Level Changes

Change Details Files
Replace AutoMapper profiles with Mapperly-based partial mapper classes.
  • Remove AutoMapper Profile subclasses in favor of partial mapper classes annotated with [Mapper].
  • Introduce MapperBase<TSource, TDestination>-derived mapper classes for GitRepository and its Create/Update input DTOs, implementing override partial Map methods for source and source+destination overloads.
  • Introduce MapperBase<TSource, TDestination>-derived mapper classes for Issue and for List to List list mapping, with corresponding partial Map method declarations.
  • Add Mapperly using directives (BBT.Aether.Mapper.Mapperly and Riok.Mapperly.Abstractions) and remove AutoMapper using directives.
templates/api/src/BBT.MyProjectName.Application/GitRepositories/GitRepositoryMapProfile.cs
templates/api/src/BBT.MyProjectName.Application/Issues/IssueMapProfile.cs
Register Mapperly mappers and switch DI configuration from AutoMapper to Mapperly.
  • Register IssueMapper and GitRepositoryMapper as scoped services in the application module DI extension.
  • Change host startup to call AddAetherMapperlyMapper instead of AddAetherAutoMapperMapper when configuring mapping for the API host.
  • Change test infrastructure startup to use AddAetherMapperlyMapper instead of the AutoMapper variant.
  • Adjust Aether-related package references in Directory.Build.props and the Application project to reference the Mapperly-based package and drop AutoMapper dependencies.
templates/api/src/BBT.MyProjectName.Application/Microsoft/Extensions/DependencyInjection/MyProjectNameApplicationModuleServiceCollectionExtensions.cs
templates/api/src/BBT.MyProjectName.HttpApi.Host/Microsoft/Extensions/DependencyInjection/MyProjectNameApiServiceCollectionExtensions.cs
templates/api/test/BBT.MyProjectName.Infrastructure.Tests/InfrastructureEntryPoint.cs
templates/api/Directory.Build.props
templates/api/src/BBT.MyProjectName.Application/BBT.MyProjectName.Application.csproj
Adjust domain model and solution configuration to support ORM and build targets.
  • Change GitRepository’s parameterless constructor from private to public to allow ORM tooling or Mapperly to instantiate the entity.
  • Add x64 and x86 solution configurations to the solution file to support additional build targets.
templates/api/src/BBT.MyProjectName.Domain/Issues/GitRepository.cs
templates/api/BBT.MyProjectName.sln

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 22, 2026

Caution

Review failed

The pull request is closed.

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'review'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 79491d9a-69f8-4ba3-ab57-83db23a6941a

📥 Commits

Reviewing files that changed from the base of the PR and between 07ef9f0 and 483059a.

📒 Files selected for processing (9)
  • templates/api/BBT.MyProjectName.sln
  • templates/api/Directory.Build.props
  • templates/api/src/BBT.MyProjectName.Application/BBT.MyProjectName.Application.csproj
  • templates/api/src/BBT.MyProjectName.Application/GitRepositories/GitRepositoryMapProfile.cs
  • templates/api/src/BBT.MyProjectName.Application/Issues/IssueMapProfile.cs
  • templates/api/src/BBT.MyProjectName.Application/Microsoft/Extensions/DependencyInjection/MyProjectNameApplicationModuleServiceCollectionExtensions.cs
  • templates/api/src/BBT.MyProjectName.Domain/Issues/GitRepository.cs
  • templates/api/src/BBT.MyProjectName.HttpApi.Host/Microsoft/Extensions/DependencyInjection/MyProjectNameApiServiceCollectionExtensions.cs
  • templates/api/test/BBT.MyProjectName.Infrastructure.Tests/InfrastructureEntryPoint.cs

📝 Walkthrough

Walkthrough

This PR migrates the object-mapping framework from AutoMapper to Mapperly throughout the application. It updates NuGet package dependencies, replaces AutoMapper profile classes with Mapperly mapper implementations, updates dependency injection registrations, and adjusts the solution configuration to support additional platform targets (x64 and x86 alongside Any CPU).

Changes

Cohort / File(s) Summary
Solution & Build Configuration
templates/api/BBT.MyProjectName.sln, templates/api/Directory.Build.props
Updated solution to include x64 and x86 platform configurations alongside Any CPU; bumped AetherPackageVersion from 1.0.19 to 1.0.20; removed AutoMapperPackageVersion property.
NuGet Dependencies
templates/api/src/BBT.MyProjectName.Application/BBT.MyProjectName.Application.csproj
Removed AutoMapper reference; replaced BBT.Aether.Application with both BBT.Aether.Application and BBT.Aether.Mapperly using the updated version.
Mapper Implementation
templates/api/src/BBT.MyProjectName.Application/GitRepositories/GitRepositoryMapProfile.cs, templates/api/src/BBT.MyProjectName.Application/Issues/IssueMapProfile.cs
Replaced AutoMapper Profile classes with Mapperly [Mapper] partial classes; introduced compile-time mapping methods with source-to-destination and destination-update overloads.
Dependency Injection Registration
templates/api/src/BBT.MyProjectName.Application/Microsoft/Extensions/DependencyInjection/MyProjectNameApplicationModuleServiceCollectionExtensions.cs, templates/api/src/BBT.MyProjectName.HttpApi.Host/Microsoft/Extensions/DependencyInjection/MyProjectNameApiServiceCollectionExtensions.cs, templates/api/test/BBT.MyProjectName.Infrastructure.Tests/InfrastructureEntryPoint.cs
Registered new Mapperly mapper classes; changed mapper registration calls from AddAetherAutoMapperMapper to AddAetherMapperlyMapper.
Model Access
templates/api/src/BBT.MyProjectName.Domain/Issues/GitRepository.cs
Changed GitRepository parameterless constructor visibility from private to public to enable ORM/framework instantiation.

Possibly Related PRs

  • burgan-tech/aether-template#3: Modifies Directory.Build.props to update the AetherPackageVersion property, directly related to the version bump in this PR.

Estimated Code Review Effort

🎯 2 (Simple) | ⏱️ ~12 minutes


🐰 A migration hops along,
AutoMapper makes way for Mapperly's song,
Compile-time mapping shines so bright,
From runtime configs to partial light!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch f/aether-upgrade

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@yilmaztayfun yilmaztayfun merged commit 92197f6 into master Mar 22, 2026
3 of 6 checks passed
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on enhancing the mapping infrastructure of the project by replacing AutoMapper with Mapperly. This change aims to improve performance and simplify the mapping definitions using Mapperly's code generation approach. Additionally, the pull request includes updates to the dependency injection setup and project configurations to accommodate the new mapping strategy.

Highlights

  • Mapperly Migration: The pull request migrates the mapping implementation from AutoMapper to Mapperly, leveraging the BBT.Aether.Mapperly package for improved performance and maintainability.
  • Dependency Injection Update: The DI configuration is updated to register the generated Mapperly mappers, replacing the previous AutoMapper registration.
  • Aether Package Version Bump: The Aether package version is bumped in Directory.Build.props, and the AutoMapper package entry is removed.
  • Solution Configuration Update: Solution configurations for x64/x86 platforms are added to the .sln file.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • The mapper registrations in AddApplicationModule only add IssueMapper and GitRepositoryMapper, but not the new GitRepositoryCreateInputMapper, GitRepositoryUpdateInputMapper, or IssueListMapper; consider either registering all concrete mappers or relying solely on AddAetherMapperlyMapper for consistency.
  • Changing GitRepository's parameterless constructor from private to public opens it up for general use; if this is only intended for ORM, consider protected or protected internal instead to reduce accidental misuse.
  • The explicit IssueListMapper : MapperBase<List<Issue>, List<IssueDto>> may be redundant if Mapperly already handles collection mappings via the IssueMapper; consider simplifying by relying on element mapping unless there is a specific need for a dedicated list mapper.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The mapper registrations in `AddApplicationModule` only add `IssueMapper` and `GitRepositoryMapper`, but not the new `GitRepositoryCreateInputMapper`, `GitRepositoryUpdateInputMapper`, or `IssueListMapper`; consider either registering all concrete mappers or relying solely on `AddAetherMapperlyMapper` for consistency.
- Changing `GitRepository`'s parameterless constructor from private to public opens it up for general use; if this is only intended for ORM, consider `protected` or `protected internal` instead to reduce accidental misuse.
- The explicit `IssueListMapper : MapperBase<List<Issue>, List<IssueDto>>` may be redundant if Mapperly already handles collection mappings via the `IssueMapper`; consider simplifying by relying on element mapping unless there is a specific need for a dedicated list mapper.

## Individual Comments

### Comment 1
<location path="templates/api/src/BBT.MyProjectName.Domain/Issues/GitRepository.cs" line_range="17" />
<code_context>
         Name = Check.NotNullOrWhiteSpace(name, nameof(name));
     }

-    private GitRepository()
+    public GitRepository()
     {
         //For orm
</code_context>
<issue_to_address>
**issue (bug_risk):** Changing the parameterless constructor from private to public weakens the aggregate’s invariants and may allow invalid state.

The private ctor ensured all `GitRepository` instances went through the `name` validation. Exposing a public parameterless ctor lets callers/ORMs bypass those checks and create invalid or partially initialized aggregates. If this is required for Mapperly/ORM support, prefer options like `internal` visibility, a factory, or mapper/ORM configuration that keeps the invariant-protecting constructor as the main entry point.
</issue_to_address>

### Comment 2
<location path="templates/api/src/BBT.MyProjectName.Application/Microsoft/Extensions/DependencyInjection/MyProjectNameApplicationModuleServiceCollectionExtensions.cs" line_range="22-24" />
<code_context>
         services.AddAetherApplication();

+        // Mappers
+        services.AddScoped<IssueMapper>();
+        services.AddScoped<GitRepositoryMapper>();
+
         // You can register your application service here.
</code_context>
<issue_to_address>
**suggestion (performance):** Mapperly mapper registrations could likely use Singleton lifetime instead of Scoped for better resource usage.

Since these Mapperly-generated mappers are stateless and thread-safe, they don’t need a scoped lifetime. Using `AddSingleton` would reduce per-request allocations without changing behavior, unless they depend on scoped services.

```suggestion
        // Mappers (Mapperly-generated, stateless, thread-safe)
        services.AddSingleton<IssueMapper>();
        services.AddSingleton<GitRepositoryMapper>();
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Name = Check.NotNullOrWhiteSpace(name, nameof(name));
}

private GitRepository()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Changing the parameterless constructor from private to public weakens the aggregate’s invariants and may allow invalid state.

The private ctor ensured all GitRepository instances went through the name validation. Exposing a public parameterless ctor lets callers/ORMs bypass those checks and create invalid or partially initialized aggregates. If this is required for Mapperly/ORM support, prefer options like internal visibility, a factory, or mapper/ORM configuration that keeps the invariant-protecting constructor as the main entry point.

Comment on lines +22 to +24
// Mappers
services.AddScoped<IssueMapper>();
services.AddScoped<GitRepositoryMapper>();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Mapperly mapper registrations could likely use Singleton lifetime instead of Scoped for better resource usage.

Since these Mapperly-generated mappers are stateless and thread-safe, they don’t need a scoped lifetime. Using AddSingleton would reduce per-request allocations without changing behavior, unless they depend on scoped services.

Suggested change
// Mappers
services.AddScoped<IssueMapper>();
services.AddScoped<GitRepositoryMapper>();
// Mappers (Mapperly-generated, stateless, thread-safe)
services.AddSingleton<IssueMapper>();
services.AddSingleton<GitRepositoryMapper>();

@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively migrates the project from AutoMapper to Mapperly, updating package dependencies, mapper definitions, and dependency injection configurations. The changes are generally well-executed. However, I've identified a critical issue where several new mappers are not registered in the DI container, which would lead to runtime errors. I've provided a suggestion to fix this. Additionally, I've noted an opportunity for simplification by potentially removing a redundant list mapper.


// Mappers
services.AddScoped<IssueMapper>();
services.AddScoped<GitRepositoryMapper>();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The new mappers for GitRepository (GitRepositoryCreateInputMapper and GitRepositoryUpdateInputMapper) are not registered for dependency injection. This will cause runtime errors when these mappers are required.

        services.AddScoped<GitRepositoryMapper>();
        services.AddScoped<GitRepositoryCreateInputMapper>();
        services.AddScoped<GitRepositoryUpdateInputMapper>();

services.AddAetherApplication();

// Mappers
services.AddScoped<IssueMapper>();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

IssueListMapper is defined in IssueMapProfile.cs but is not registered here for dependency injection. If it's intended to be used, it should be registered.

However, you should also consider if this mapper is necessary. Mapperly automatically handles mapping of collections if a mapping for the element type is defined (which IssueMapper provides). You might be able to remove IssueListMapper entirely for a simpler design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant