Skip to main content

AlephMapper by Yevhen Cherkes

NuGet / site data

Nuget GitHub last commit GitHub Repo stars

Details

Info

info

Name: AlephMapper

Source generator for creating projectable companions

Author: Yevhen Cherkes

NuGet: https://www.nuget.org/packages/AlephMapper/

You can find more details at https://github.com/Raffinert/AlephMapper

Source: https://github.com/Raffinert/AlephMapper

Author

note

Yevhen Cherkes Alt text

Original Readme

note

Stand With Ukraine

Terms of use?

By using this project or its source code, for any purpose and in any shape or form, you grant your implicit agreement to all the following statements:

  • You condemn Russia and its military aggression against Ukraine
  • You recognize that Russia is an occupant that unlawfully invaded a sovereign state
  • You support Ukraine's territorial integrity, including its claims over temporarily occupied territories of Crimea and Donbas
  • You reject false narratives perpetuated by Russian state propaganda

To learn more about the war and how you can help, click here. Glory to Ukraine!

AlephMapper

NuGet NuGet Downloads License

AlephMapper is a C# source generator for reusable manual mappings. Write one expression-bodied mapping method and generate companion methods for EF Core projections and optional update-in-place mapping from the same code.

Use it when you want hand-written mapping logic without maintaining a separate Expression<Func<...>> for queries or a second method for updating existing objects.

Features
  • Single-source mappings - use one mapping method for runtime mapping, query projection, and update variants.
  • EF Core-friendly projections - generate Expression<Func<TSource, TDestination>> methods for .Select(...).
  • Method inlining - reuse small helper methods in mappings and let AlephMapper inline them into generated code.
  • Configurable null handling - choose how null-conditional access (?.) is handled in generated expressions.
  • Update-in-place mapping - mutate existing destination instances, including EF Core tracked entities.
Install

Using the .NET CLI:

dotnet add package AlephMapper

Using PackageReference:

<PackageReference Include="AlephMapper" Version="0.5.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

With Central Package Management:

<!-- Directory.Packages.props -->
<PackageVersion Include="AlephMapper" Version="0.5.5" />

<!-- Project file -->
<PackageReference Include="AlephMapper">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

When referencing AlephMapper directly from source, add it as an analyzer-only project reference:

<ProjectReference Include="..\path\to\AlephMapper.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />

PrivateAssets="all" keeps AlephMapper from flowing transitively to consumers of your library, and IncludeAssets ensures the analyzer/source-generator assets are available at build time.

Requirements
  • Mapping methods must be static, expression-bodied, and declared in a static partial class.
Quick Start

Add using AlephMapper;, then mark a mapping method or mapper class with [Expressive].

using AlephMapper;

public static partial class PersonMapper
{
[Expressive]
public static PersonDto MapToPerson(Employee employee) => new()
{
Id = employee.EmployeeId,
FullName = GetFullName(employee),
Email = employee.ContactInfo.Email,
Department = employee.Department.Name
};

public static string GetFullName(Employee employee) =>
employee.FirstName + " " + employee.LastName;
}

AlephMapper generates a projection companion method:

public static partial class PersonMapper
{
public static Expression<Func<Employee, PersonDto>> MapToPersonExpression() =>
employee => new PersonDto
{
Id = employee.EmployeeId,
FullName = employee.FirstName + " " + employee.LastName,
Email = employee.ContactInfo.Email,
Department = employee.Department.Name
};
}

Use the generated expression in EF Core queries:

var people = await dbContext.Employees
.Select(PersonMapper.MapToPersonExpression())
.ToListAsync();

Use the original method for in-memory mapping:

var employee = GetEmployee();
var dto = PersonMapper.MapToPerson(employee);
Null Handling

C# null-conditional access (?.) is not directly supported in expression trees. AlephMapper lets you choose how to handle it.

[Expressive(NullConditionalRewrite = NullConditionalRewrite.Rewrite)]
public static partial class PersonMapper
{
public static PersonSummary GetSummary(Person person) => new()
{
Name = person.Name,
City = person.Address?.City,
HasAddress = person.Address != null
};
}

Available policies:

PolicyBehavior
NoneReports unsupported null-conditional usage.
IgnoreRemoves null-conditional access, for example person.Address?.City becomes person.Address.City.
RewriteEmits explicit null checks, for example person.Address != null ? person.Address.City : null.

Ignore is the default. Use Rewrite when you want generated expressions to preserve null-safe behavior.

Update Existing Objects

Mark a mapping with [Updatable] to generate an overload that writes into an existing destination instance.

using AlephMapper;

public static partial class PersonMapper
{
[Updatable]
public static Person MapToPerson(PersonUpdateDto dto) => new()
{
FirstName = dto.FirstName,
LastName = dto.LastName,
Email = dto.Email
};
}

Generated usage:

var person = await db.People.FindAsync(id);

PersonMapper.MapToPerson(dto, target: person);

await db.SaveChangesAsync();

This is useful with EF Core change tracking because the tracked entity instance is preserved.

Collection properties are skipped by default. To update collections, configure the policy:

[Updatable(CollectionProperties = CollectionPropertiesPolicy.Update)]
public static Person MapToPerson(PersonUpdateDto dto) => new()
{
Orders = dto.Orders.Select(OrderMapper.MapToOrder).ToList()
};
How It Works

For each [Expressive] method, AlephMapper generates a method named <OriginalMethodName>Expression() returning Expression<Func<...>>.

public static PersonDto MapToPerson(Employee employee) => ...

public static Expression<Func<Employee, PersonDto>> MapToPersonExpression() => ...

For each [Updatable] method, AlephMapper generates an overload with a target parameter.

public static PersonDto MapToPerson(Employee employee) => ...

public static PersonDto MapToPerson(Employee employee, PersonDto target) => ...

Helper methods in the same mapper class are inlined where possible.

Supported Mapping Shape

Methods must be:

  • expression-bodied (=>)
  • static
  • declared in a static partial class
  • visible to the source generator in the current compilation

AlephMapper is best suited for object initializer mappings and small helper methods that can be inlined into generated expressions.

Troubleshooting

######### Generated method is missing

Check that the mapper class is static partial, the method is expression-bodied, and the method or containing class has [Expressive] or [Updatable].

######### NullReferenceException after using ?.

The default null policy is Ignore, which removes null-conditional access in generated expressions. Use:

[Expressive(NullConditionalRewrite = NullConditionalRewrite.Rewrite)]

######### Updatable mapping is skipped for value types

[Updatable] is intended for reference-type destinations. Value types are copied by value, so update-in-place semantics are not useful.

######### Circular helper calls

Generation is skipped when AlephMapper detects circular references between mapping/helper methods. Break the cycle or keep part of the logic outside the generated mapping path.

######### Inspect generated code

Add this to your project file:

<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>

Generated files are emitted under the compiler-generated files output directory for your project.

Comparison
ToolMain styleAlephMapper difference
AutoMapperRuntime configuration and conventionsAlephMapper keeps mappings as ordinary C# methods.
MapsterConvention/configuration mapping with code generation optionsAlephMapper focuses on source-generating companions from manual mappings.
EntityFrameworkCore.ProjectablesProjectable members for EF CoreAlephMapper targets mapping methods and update overloads.
ExpressionifyExpression expansionAlephMapper is mapping-oriented and also supports update-in-place generation.
Examples
Contributing

Contributions are welcome.

  1. Fork the repository.
  2. Create a feature branch.
  3. Make the change.
  4. Add or update tests.
  5. Run the test suite.
  6. Open a pull request.
License

This project is licensed under the MIT License. See LICENSE for details.

Acknowledgments

About

note

AlephMapper helps you define LINQ-translatable object mappers for EF Core.

It turns a normal C# mapping method into an expression that can be embedded in queries, so your entity-to-DTO projection can run inside the database query instead of after materialization.

This is useful for cleaner projection code, avoiding hand-written select expressions, and keeping mapping logic reusable across queries.

How to use

Example (source csproj, source files)

This is the CSharp Project that references AlephMapper

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AlephMapper" Version="0.5.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.9" />

</ItemGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
</Project>

Generated Files

Those are taken from $(BaseIntermediateOutputPath)\GX

using System;

namespace AlephMapper;

/// <summary>
/// Configures how null-conditional operators are handled
/// </summary>
public enum NullConditionalRewrite
{
/// <summary>
/// Don't rewrite null conditional operators (Default behavior).
/// Usage of null conditional operators is thereby not allowed
/// </summary>
None,

/// <summary>
/// Ignore null-conditional operators in the generated expression tree
/// </summary>
/// <remarks>
/// <c>(A?.B)</c> is rewritten as expression: <c>(A.B)</c>
/// </remarks>
Ignore,

/// <summary>
/// Translates null-conditional operators into explicit null checks
/// </summary>
/// <remarks>
/// <c>(A?.B)</c> is rewritten as expression: <c>(A != null ? A.B : null)</c>
/// </remarks>
Rewrite
}

/// <summary>
/// Marks a class to generate expressive companion methods.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class ExpressiveAttribute : Attribute
{
/// <summary>
/// Get or set how null-conditional operators are handled
/// </summary>
public NullConditionalRewrite NullConditionalRewrite \{ get; set; \} = NullConditionalRewrite.Ignore;
}

/// <summary>
/// Marks a class to generate update companion methods.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class UpdatableAttribute : Attribute
{
/// <summary>
/// Gets or sets the policy for handling collection updates during mapping operations
/// </summary>
public CollectionPropertiesPolicy CollectionProperties \{ get; set; \} = CollectionPropertiesPolicy.Skip;
}

/// <summary>
/// Defines the policy for handling collection updates during mapping operations
/// </summary>
public enum CollectionPropertiesPolicy
{
/// <summary>
/// Skip collection updates - collections will not be modified during mapping
/// </summary>
Skip,

/// <summary>
/// Update collections - collections will be updated during mapping operations
/// </summary>
Update
}

Useful

Download Example (.NET C#)

Share AlephMapper

https://ignatandrei.github.io/RSCG_Examples/v2/docs/AlephMapper

Category "Database" has the following generators:

1 AlephMapper Nuget GitHub Repo stars 2026-06-29

2 Breezy Nuget GitHub Repo stars 2023-08-09

3 Dapper.AOT Nuget GitHub Repo stars 2024-12-02

4 EntityLengths.Generator Nuget GitHub Repo stars 2025-02-19

5 Facet.Search Nuget GitHub Repo stars 2025-12-17

6 Finch.Generators Nuget GitHub Repo stars 2025-08-10

7 Gedaq Nuget GitHub Repo stars 2023-07-29

8 TableStorage Nuget GitHub Repo stars 2024-06-01

9 Unflat Nuget GitHub Repo stars 2025-08-18

See category

Database