ObjectMap.NET
1.0.7
See the version list below for details.
dotnet add package ObjectMap.NET --version 1.0.7
NuGet\Install-Package ObjectMap.NET -Version 1.0.7
<PackageReference Include="ObjectMap.NET" Version="1.0.7" />
<PackageVersion Include="ObjectMap.NET" Version="1.0.7" />
<PackageReference Include="ObjectMap.NET" />
paket add ObjectMap.NET --version 1.0.7
#r "nuget: ObjectMap.NET, 1.0.7"
#:package ObjectMap.NET@1.0.7
#addin nuget:?package=ObjectMap.NET&version=1.0.7
#tool nuget:?package=ObjectMap.NET&version=1.0.7
ObjectMap.NET
A lightweight, convention-based object mapper for modern .NET.
NuGet: ObjectMap.NET
Namespaces: SimpleMapper.*
Target framework: net10.0
ObjectMap.NET is designed for explicit maps — every (source → destination) pair is registered in a profile. Convention handles the common cases; fluent configuration covers the rest.
Installation
dotnet add package ObjectMap.NET
Local project reference:
<ProjectReference Include="path\to\SR.ObjectMapper.NET.csproj" />
Quick start
1. Register the mapper
using SimpleMapper.Mapper.DependencyInjection;
using SimpleMapper.Mapper.Profiles;
services.AddSRSimpleMapper(cfg =>
{
cfg.RegisterProfile(new MyAppMappingProfile());
});
Optional global settings:
services.AddSRSimpleMapper(cfg =>
{
cfg.DestinationMemberNaming = NamingConventions.SnakeCaseDestination;
cfg.EnableAutoFlattening = true;
cfg.RegisterProfile<MyAppMappingProfile>();
});
2. Define a profile
using SimpleMapper.Mapper.Profiles;
public class MyAppMappingProfile : Profile
{
protected override void ConfigureMaps()
{
CreateMap<OrderDto, OrderEntity>()
.ForMember(d => d.Total, o => o.MapFrom(s => s.Lines.Sum(l => l.Amount))
.BeforeMap((dto, entity) => { /* runs before members are assigned */ })
.AfterMap((dto, entity) => { /* runs after mapping completes */ })
.ReverseMap();
CreateMap<LineItemDto, LineItemEntity>();
}
}
3. Inject and map
public class OrderService(ISRSimpleMapper mapper)
{
public OrderEntity ToEntity(OrderDto dto) =>
mapper.Map<OrderDto, OrderEntity>(dto);
}
Core API (ISRSimpleMapper)
| Method | Purpose |
|---|---|
Map<TDestination>(object source) |
Map using the runtime type of source. |
Map<TSource, TDestination>(TSource source) |
Map with compile-time source and destination types (preferred). |
Map<TSource, TDestination>(TSource source, TDestination destination) |
Map into an existing instance (update / patch). |
ProjectTo<TSource, TDestination>(IQueryable<TSource> query) |
Project a query using a cached expression tree (EF Core–friendly). |
Nulls: Map<TSource, TDestination>(source) returns default when source is null.
Map(source, destination) throws ArgumentNullException if either argument is null.
Configuration
MapperConfiguration
| Property | Description |
|---|---|
DestinationMemberNaming |
How destination member names relate to source names (default: PascalCase). |
SourceMemberNaming |
Additional source-side naming convention for property lookup. |
EnableAutoFlattening |
When true, nested source properties can populate flat destination members (default: true). |
Built-in naming conventions (NamingConventions):
PascalCase— default, same names on both sides.SnakeCaseDestination— source PascalCase → destination snake_case (e.g.UserName→user_name).SnakeCaseSource— source snake_case → destination PascalCase.
Profile
Override ConfigureMaps() and call CreateMap<TSource, TDestination>() for every pair you map.
Fluent mapping API
CreateMap<TSource, TDestination>()
Registers a one-way map. Matching is by convention (name + compatible types), plus flattening and naming rules below.
ReverseMap()
Registers the inverse map TDestination → TSource and returns a TypeMapExpression<TDestination, TSource> so chained ForMember / hooks configure the reverse direction.
- Ignored members are mirrored on the reverse map (a later
ForMember(...).MapFrom(...)on the reverse expression clears that ignore). - Flattened members are reversed into nested paths (e.g.
City→Address.City). BeforeMap/AfterMaphooks are copied with swapped(source, destination)arguments so forward hooks run on the correct instances during reverse mapping.- Name-matched members with incompatible types (e.g.
DbUserRole→string) are not auto-wired on reverse; use explicitForMember(e.g.src.Role.Name). - Nested complex members (e.g.
DbTopic→TopicNameResponse) are not cast by convention; they are mapped at runtime through the registered nestedCreateMap/ReverseMap.
ForMember(dest => dest.Member, opt => { ... })
| Call | Effect |
|---|---|
opt.Ignore() |
Skip this destination member. |
opt.MapFrom(src => ...) |
Set the member from a custom expression. |
BeforeMap / AfterMap
CreateMap<Entity, Dto>()
.BeforeMap((src, dest) => { /* destination exists; members not yet assigned */ })
.AfterMap((src, dest) => { /* all mapping complete */ });
On create-new maps, BeforeMap runs after an empty destination is created and before any members are assigned.
DisableAutoFlattening()
Disables automatic flattening for a specific map (e.g. when Address.City must not map to City).
Auto-flattening
When enabled, nested scalar properties can populate flat destination members:
// Entity.Address.City → FlatDto.City
CreateMap<Entity, FlatDto>();
- Supports multi-level paths (e.g.
A.B.C.Name→Name). - Ambiguous paths (multiple nested matches) throw
MappingException— use explicitForMemberor disable flattening. - Works in runtime mapping, compiled maps, reverse maps, and
ProjectTo.
How mapping works
- Create destination (parameterless constructor, or uninitialized object when none exists).
BeforeMaphooks run.- Compiled assignment (
CompileToExisting) sets scalar and simple custom members. - Post-compile runtime handles flatten-reverse members, complex custom
MapFrom, nested objects, and collections. AfterMaphooks run.
Collections and nested objects are mapped at runtime using registered element/nested type maps. Flat scalars use compiled expressions for speed.
Collections
- Different element types are mapped element-wise (never copied by reference).
- Register
CreateMap<TSourceElement, TDestinationElement>for each element pair. - Strings are not treated as collections.
CreateMap<OrderDto, OrderEntity>();
CreateMap<LineItemDto, LineItemEntity>();
// OrderDto.Lines → OrderEntity.Lines
Supported targets include List<T>, arrays, ICollection<T>, HashSet<T>, Queue<T>, and Stack<T>.
Mapping into an existing object
mapper.Map(orderDto, trackedEntity);
Use for EF updates: load the entity, map the DTO onto it.
- Flattened reverse members (e.g.
City→Address.City) are supported. - Collection properties are updated via nested mapping (not in the initial convention loop).
- Ignored and explicit
ForMembermembers are respected.
ProjectTo (database projection)
var dtos = dbContext.Orders
.AsNoTracking()
.ProjectTo<OrderEntity, OrderDto>(mapper)
.ToList();
- Builds a cached LINQ expression tree per type map (not per-row
Mapcalls). - Works with EF Core for convention-based and flattening maps.
- Simple computed
MapFromexpressions (e.g.s => s.X * 2) can be included when translatable. - Throws
MappingExceptionat build time when a configured member cannot be translated. - Arbitrary method calls in
MapFrommay build an expression that EF cannot translate to SQL — test your queries.
Prefer ProjectTo for list/query endpoints instead of loading entities and calling Map in memory.
Dependency injection
No changes required beyond registration:
services.AddSRSimpleMapper(cfg => cfg.RegisterProfile(new MyAppMappingProfile>());
ISRSimpleMapper is registered as singleton; MapperConfiguration and compiled maps are built once.
Entity Framework notes
- Updates:
Map(dto, trackedEntity)— do not create a new entity and attach. - Queries: Use
ProjectTowithAsNoTracking()for read-only lists. - Owned types / nested value objects: Ensure your EF model matches flatten paths (e.g.
OwnsOne(e => e.Address)). - Proxies: Nested mapping normalizes
Castle.Proxiesto base types when resolving nested maps.
Performance guidance
| Scenario | Recommendation |
|---|---|
| API list endpoints | Paginate at the DB; use ProjectTo. |
| Flat DTOs | Fast — compiled scalar mapping. |
| Nested graphs in memory | Slower — reflection per object; fine for small/medium batches. |
| 100k+ nested records | Avoid mapping entire graphs in one shot; process in chunks. |
Requirements checklist
- Register
CreateMap<Source, Dest>for every pair you callMapwith. - Register element maps for collection properties with different element types.
- Use
Ignore()for properties maintained elsewhere (passwords, manual navigations). - Use
ForMember/MapFromfor computed or renamed members. - Use explicit
ForMemberorDisableAutoFlattening()when flatten paths are ambiguous.
Troubleshooting
| Symptom | Likely cause |
|---|---|
No map found from X to Y |
Missing CreateMap<X, Y> for the exact CLR types. |
Ambiguous flattening for member 'X' |
Multiple nested paths match; add explicit ForMember or disable flattening. |
Cannot translate member 'X' to a database projection |
MapFrom cannot be expressed for ProjectTo; simplify or map in memory. |
MappingException from MapFrom |
Null reference or invalid expression in custom mapping. |
| Collection empty | Missing element CreateMap, or property ignored / skipped. |
| Reverse map missing nested value | Ensure ReverseMap() is called; flattened reverse requires auto-flatten on forward map. |
EF query fails after ProjectTo |
Expression uses non-translatable method calls; inspect SQL or simplify MapFrom. |
License
MIT
Author
Shohanur Rahman
LinkedIn
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.0.7: ReverseMap, multi-level auto-flattening, naming conventions, BeforeMap/AfterMap, SQL-friendly ProjectTo (cached expression trees), deep flatten and map-into-existing reverse-flatten fixes, ambiguous flatten errors, SourceMemberNaming, MappingException for failed MapFrom/ProjectTo. See PackageReleaseNotes.md.