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 Facet.Search Nuget GitHub Repo stars 2025-12-17

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

6 Gedaq Nuget GitHub Repo stars 2023-07-29

7 TableStorage Nuget GitHub Repo stars 2024-06-01

8 Unflat Nuget GitHub Repo stars 2025-08-18

See category​

Database