Mapsicle.EntityFramework
1.0.1
See the version list below for details.
dotnet add package Mapsicle.EntityFramework --version 1.0.1
NuGet\Install-Package Mapsicle.EntityFramework -Version 1.0.1
<PackageReference Include="Mapsicle.EntityFramework" Version="1.0.1" />
<PackageVersion Include="Mapsicle.EntityFramework" Version="1.0.1" />
<PackageReference Include="Mapsicle.EntityFramework" />
paket add Mapsicle.EntityFramework --version 1.0.1
#r "nuget: Mapsicle.EntityFramework, 1.0.1"
#:package Mapsicle.EntityFramework@1.0.1
#addin nuget:?package=Mapsicle.EntityFramework&version=1.0.1
#tool nuget:?package=Mapsicle.EntityFramework&version=1.0.1
Mapsicle ๐ฆ
Mapsicle is a high-performance, modular object mapping ecosystem for .NET. Choose only what you need:
| Package | Purpose | Dependencies |
|---|---|---|
| Mapsicle | Zero-config mapping | None |
| Mapsicle.Fluent | Fluent configuration | Mapsicle |
| Mapsicle.EntityFramework | EF Core ProjectTo<T>() |
Mapsicle.Fluent |
"The fastest mapping is the one you don't have to configure."
๐ Why Switch from AutoMapper?
โ ๏ธ AutoMapper is now commercial software. As of version 13+, AutoMapper requires a paid license. Mapsicle is 100% free and MPL 2.0 licensed forever.
| Feature | Mapsicle | AutoMapper |
|---|---|---|
| License | MPL 2.0 (Free) | Commercial |
| Dependencies | 0 | 5+ |
| Setup Required | None | Profiles, DI |
| Circular Refs | Handled | Crash |
| Binary Size | ~25KB | ~500KB+ |
| Memory Bounded | LRU Option | No |
| Cache Statistics | Yes | No |
๐ฆ Quick Start
Complete Example (Copy & Paste)
using Mapsicle;
// 1. Define your types
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
public class UserDto
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
// 2. Map - that's it! No configuration needed
var user = new User { Id = 1, FirstName = "John", LastName = "Doe", Email = "john@example.com" };
var dto = user.MapTo<UserDto>(); // FirstName and LastName copied automatically
// 3. Map collections
List<User> users = GetUsers();
List<UserDto> dtos = users.MapTo<UserDto>(); // Entire list mapped
Requirements: .NET Standard 2.0+ or .NET 6.0+
Installation: dotnet add package Mapsicle
Which Package Do I Need?
Do you need EF Core query translation (ProjectTo)?
โโ YES โ Install: Mapsicle + Mapsicle.Fluent + Mapsicle.EntityFramework
โโ NO
โโ Do you need custom mapping logic (ForMember, hooks)?
โ โโ YES โ Install: Mapsicle + Mapsicle.Fluent
โ โโ NO โ Install: Mapsicle (core only - zero config)
| Scenario | Packages Needed |
|---|---|
| Simple POCO mapping | Mapsicle |
| API DTOs with transformations | Mapsicle.Fluent (includes core) |
| EF Core with SQL projection | All three packages |
๐ Benchmark Results
Real benchmarks on Apple M1, .NET 8.0, BenchmarkDotNet v0.13.12:
Core Mapping Performance
| Scenario | Manual | Mapsicle | AutoMapper | Winner |
|---|---|---|---|---|
| Single Object | 31 ns | 59 ns | 72 ns | โญ Mapsicle (+22%) |
| Flattening | 14 ns | 29 ns | 56 ns | โญ Mapsicle (+93%) |
| Collection (100) | 3.5 ฮผs | 5.5 ฮผs | 4.0 ฮผs | AutoMapper |
Edge Case Performance
| Scenario | Mapsicle | AutoMapper | Notes |
|---|---|---|---|
| Deep Nesting (15 levels) | โ Safe | โ Safe | Both handle with MaxDepth |
| Circular References | โ Handled | โ Crashes | Mapsicle wins |
| Large Collection (10K) | 4 ms | 4 ms | Comparable |
| Parallel (1000 threads) | โ Thread-safe | โ Thread-safe | Lock-free reads |
Performance Optimizations (v1.1+)
| Optimization | Improvement | Status |
|---|---|---|
| Lock-free cache reads | Eliminates contention | โ |
| Collection mapper caching | +20% for collections (v1.1) | โ |
| PropertyInfo caching | +15% faster cold starts | โ |
| Primitive fast path | Skips depth tracking | โ |
| Cached compiled actions | No runtime reflection | โ |
| LRU cache option | Memory-bounded in long-run apps | โ |
| Collection pre-allocation | Capacity hints for known sizes | โ |
Memory & Cache Statistics (v1.1+)
// Enable memory-bounded caching
Mapper.UseLruCache = true;
Mapper.MaxCacheSize = 1000; // Default
// Monitor cache performance
var stats = Mapper.CacheInfo();
Console.WriteLine($"Cache entries: {stats.Total}");
Console.WriteLine($"Hit ratio: {stats.HitRatio:P1}"); // Only when LRU enabled
Console.WriteLine($"Hits: {stats.Hits}, Misses: {stats.Misses}");
| Feature | Mapsicle (Unbounded) | Mapsicle (LRU) | AutoMapper |
|---|---|---|---|
| Memory Bounded | โ | โ | โ |
| Cache Statistics | Entry count only | Full stats | โ |
| Configurable Limit | โ | โ | โ |
| Lock-Free Reads | โ | โ | Partial |
Smoke Test Results (10,000 mappings)
โ Core: 10,000 mappings in 19ms
โ Fluent: 10,000 mappings in 10ms
โ Deep nesting (10 levels): 1,000 mappings in 3ms
โ Large collection (10,000 items): 4ms
๐ก Key Insight: Mapsicle wins on simple/flattened mappings and safety. Both vastly outperform reflection-based approaches.
Run Benchmarks Yourself
cd tests/Mapsicle.Benchmarks
dotnet run -c Release # Full suite
dotnet run -c Release -- --quick # Smoke test
dotnet run -c Release -- --edge # Edge cases only
๐ฆ Installation
# Core package - zero config
dotnet add package Mapsicle
# Fluent configuration (optional)
dotnet add package Mapsicle.Fluent
# EF Core ProjectTo (optional)
dotnet add package Mapsicle.EntityFramework
โก Package 1: Mapsicle (Core)
Basic Mapping
using Mapsicle;
var dto = user.MapTo<UserDto>(); // Single object
List<UserDto> dtos = users.MapTo<UserDto>(); // Collection
var flat = order.MapTo<OrderFlatDto>(); // Auto-flattening
Attributes
public class UserDto
{
[MapFrom("UserName")] // Map from different property
public string Name { get; set; }
[IgnoreMap] // Never mapped
public string Secret { get; set; }
}
Stability Features (NEW!)
// Cycle Detection - no more StackOverflow
Mapper.MaxDepth = 32; // Default, configurable
// Validation at startup
Mapper.AssertMappingValid<User, UserDto>();
// Logging
Mapper.Logger = Console.WriteLine;
// Memory-bounded caching (prevents memory leaks in long-running apps)
Mapper.UseLruCache = true; // Enable LRU cache
Mapper.MaxCacheSize = 1000; // Limit cache entries
// Cache statistics
var stats = Mapper.CacheInfo();
Console.WriteLine($"Hit ratio: {stats.HitRatio:P1}");
// Scoped instances with isolated caches
using var mapper = MapperFactory.Create();
var dto = mapper.MapTo<UserDto>(user); // Uses isolated cache
โก Package 2: Mapsicle.Fluent
Basic Configuration
using Mapsicle.Fluent;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<User, UserDto>()
.ForMember(d => d.FullName, opt => opt.MapFrom(s => $"{s.First} {s.Last}"))
.ForMember(d => d.Password, opt => opt.Ignore())
.ForMember(d => d.Status, opt => opt.Condition(s => s.IsActive));
});
config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();
DI Integration (NEW!)
// In Program.cs
services.AddMapsicle(cfg =>
{
cfg.CreateMap<User, UserDto>();
}, validateConfiguration: true);
// In your service
public class UserService(IMapper mapper)
{
public UserDto GetUser(User user) => mapper.Map<UserDto>(user);
}
Lifecycle Hooks (NEW!)
cfg.CreateMap<Order, OrderDto>()
.BeforeMap((src, dest) => dest.CreatedAt = DateTime.UtcNow)
.AfterMap((src, dest) => dest.WasProcessed = true);
Polymorphic Mapping (NEW!)
cfg.CreateMap<Vehicle, VehicleDto>()
.Include<Car, CarDto>()
.Include<Truck, TruckDto>();
Custom Construction (NEW!)
cfg.CreateMap<Order, OrderDto>()
.ConstructUsing(src => OrderFactory.Create(src.Type));
Global Type Converters (NEW!)
cfg.CreateConverter<Money, decimal>(m => m.Amount);
cfg.CreateConverter<Money, string>(m => $"{m.Currency} {m.Amount}");
โก Package 3: Mapsicle.EntityFramework
ProjectTo<T>() that translates to SQLโno in-memory loading!
using Mapsicle.EntityFramework;
var dtos = await _context.Users
.Where(u => u.IsActive)
.ProjectTo<UserEntity, UserDto>()
.ToListAsync();
// Flattening in SQL: Customer.Name โ CustomerName
var orders = _context.Orders
.ProjectTo<OrderEntity, OrderFlatDto>()
.ToList();
ProjectTo with Fluent Configuration (NEW!)
// ForMember expressions are translated to SQL!
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Order, OrderDto>()
.ForMember(d => d.CustomerName, opt => opt.MapFrom(s => s.Customer.FirstName + " " + s.Customer.LastName))
.ForMember(d => d.Total, opt => opt.MapFrom(s => s.Lines.Sum(l => l.Quantity * l.UnitPrice)));
});
// These expressions translate to SQL queries
var orders = _context.Orders.ProjectTo<Order, OrderDto>(config).ToList();
๐ง Migration from AutoMapper
API Compatibility
| AutoMapper | Mapsicle |
|---|---|
CreateMap<S,D>() |
Same! |
ForMember().MapFrom() |
Same! |
.Ignore() |
Same! |
BeforeMap/AfterMap |
Same! |
Include<Derived>() |
Same! |
ConstructUsing() |
Same! |
services.AddAutoMapper() |
services.AddMapsicle() |
_mapper.Map<T>() |
mapper.Map<T>() or obj.MapTo<T>() |
Step-by-Step Migration Guide
1. Identify Your AutoMapper Usage
Simple mappings (no profiles) โ Use core Mapsicle package
Profiles with configuration โ Use Mapsicle.Fluent
EF Core ProjectTo โ Use Mapsicle.EntityFramework
2. Install Packages
dotnet remove package AutoMapper
dotnet remove package AutoMapper.Extensions.Microsoft.DependencyInjection
dotnet add package Mapsicle.Fluent # Includes core
3. Convert Profiles to Configuration
Before (AutoMapper):
public class UserProfile : Profile
{
public UserProfile()
{
CreateMap<User, UserDto>()
.ForMember(d => d.FullName, opt => opt.MapFrom(s => s.FirstName + " " + s.LastName));
}
}
After (Mapsicle):
// In Program.cs/Startup.cs
services.AddMapsicle(cfg =>
{
cfg.CreateMap<User, UserDto>()
.ForMember(d => d.FullName, opt => opt.MapFrom(s => s.FirstName + " " + s.LastName));
}, validateConfiguration: true);
4. Update DI Registration
Before:
services.AddAutoMapper(typeof(UserProfile).Assembly);
After:
services.AddMapsicle(cfg =>
{
cfg.CreateMap<User, UserDto>();
cfg.CreateMap<Order, OrderDto>();
// ... all your mappings
}, validateConfiguration: true);
5. Update Mapping Calls
Before:
public class UserService
{
private readonly IMapper _mapper;
public UserService(IMapper mapper) => _mapper = mapper;
public UserDto GetUser(User user) => _mapper.Map<UserDto>(user);
}
After (same interface!):
public class UserService
{
private readonly IMapper _mapper;
public UserService(IMapper mapper) => _mapper = mapper;
// Option 1: Same as AutoMapper
public UserDto GetUser(User user) => _mapper.Map<UserDto>(user);
// Option 2: Extension method (no DI needed for simple cases)
public UserDto GetUser(User user) => user.MapTo<UserDto>();
}
Known Incompatibilities
โ Not Supported:
- Custom naming conventions (PascalCase โ camelCase)
IMemberValueResolverinterface - useResolveUsing(func)insteadITypeConverterinterface - useCreateConverter<T, U>()instead- Conditional mapping with complex predicates
- MaxDepth per individual mapping (only global
Mapper.MaxDepth)
โ ๏ธ Behavioral Differences:
- Circular references: AutoMapper throws exception, Mapsicle returns default value
- Unmapped properties: Both ignore, but Mapsicle has
GetUnmappedProperties<T, U>()for validation - Null handling: Both return null for null source, but Mapsicle is more aggressive with null-safe navigation
๐ ๏ธ Troubleshooting
Common Issues
Issue: Properties Not Mapping
Symptom: Destination properties remain default/null after mapping
Causes & Solutions:
Property name mismatch
// Problem: Source has "UserName", destination has "Name" // Solution 1: Use [MapFrom] attribute public class UserDto { [MapFrom("UserName")] public string Name { get; set; } } // Solution 2: Use Fluent configuration cfg.CreateMap<User, UserDto>() .ForMember(d => d.Name, opt => opt.MapFrom(s => s.UserName));Property not readable/writable
// โ Won't map (no setter) public string Name { get; } // โ Will map public string Name { get; set; } // โ Also works (init setter) public string Name { get; init; }Type incompatibility
// Check which properties can't map var unmapped = Mapper.GetUnmappedProperties<User, UserDto>(); Console.WriteLine($"Unmapped: {string.Join(", ", unmapped)}");
Issue: StackOverflowException
Cause: Circular references exceeding MaxDepth (default 32)
Solutions:
// Solution 1: Increase depth limit
Mapper.MaxDepth = 64;
// Solution 2: Enable logging to see depth warnings
Mapper.Logger = msg => Console.WriteLine($"[Mapsicle] {msg}");
// Solution 3: Use [IgnoreMap] to break cycle
public class User
{
public int Id { get; set; }
[IgnoreMap] // Don't map back to parent
public List<Order> Orders { get; set; }
}
Issue: Poor Collection Mapping Performance
Symptom: Mapping 10,000+ items is slow
Solutions:
// โ Don't: Map items individually
foreach (var user in users)
{
dtos.Add(user.MapTo<UserDto>());
}
// โ
Do: Map entire collection
var dtos = users.MapTo<UserDto>(); // 20% faster with cached mapper
// โ
Do: Pre-warm cache at startup for frequently used types
new User().MapTo<UserDto>();
new Order().MapTo<OrderDto>();
Issue: Memory Growth in Long-Running Apps
Symptom: Memory usage grows over time
Cause: Unbounded cache with many dynamic type combinations
Solution:
// Enable memory-bounded LRU cache
Mapper.UseLruCache = true;
Mapper.MaxCacheSize = 1000; // Adjust based on # of unique type pairs
// Monitor cache performance
var stats = Mapper.CacheInfo();
if (stats.HitRatio < 0.8)
{
// Consider increasing cache size
Mapper.MaxCacheSize = 2000;
}
Issue: EF Core ProjectTo Not Working
Symptom: Exception thrown or results incorrect
Common Causes:
Missing configuration
// โ Don't use convention mapping with complex expressions var dtos = context.Orders.ProjectTo<Order, OrderDto>().ToList(); // โ Pass configuration for ForMember expressions var config = new MapperConfiguration(cfg => { cfg.CreateMap<Order, OrderDto>() .ForMember(d => d.CustomerName, opt => opt.MapFrom(s => s.Customer.Name)); }); var dtos = context.Orders.ProjectTo<Order, OrderDto>(config).ToList();Non-translatable expressions
// โ Method calls that don't translate to SQL cfg.CreateMap<User, UserDto>() .ForMember(d => d.Name, opt => opt.ResolveUsing(u => FormatName(u))); // โ Use expressions that translate to SQL cfg.CreateMap<User, UserDto>() .ForMember(d => d.Name, opt => opt.MapFrom(u => u.FirstName + " " + u.LastName));
Debugging Tips
// 1. Enable verbose logging
Mapper.Logger = msg => _logger.LogDebug($"[Mapsicle] {msg}");
// 2. Validate mapping at startup
#if DEBUG
Mapper.AssertMappingValid<User, UserDto>();
#endif
// 3. Check configuration in fluent mapper
config.AssertConfigurationIsValid();
// 4. Monitor cache statistics
var stats = Mapper.CacheInfo();
_logger.LogInformation($"Cache: {stats.Total} entries, Hit ratio: {stats.HitRatio:P1}");
// 5. Use MapperFactory for isolated testing
using var mapper = MapperFactory.Create(new MapperOptions
{
MaxDepth = 16,
Logger = Console.WriteLine
});
var dto = mapper.MapTo<UserDto>(user);
โ ๏ธ Known Limitations
Feature Limitations
โ Not Supported:
- Custom naming conventions (e.g., PascalCase โ camelCase)
- Async mapping operations
- Source/destination value injection (context passing)
- Open generic types
- Explicit type conversion configuration beyond built-ins
โ ๏ธ Partial Support:
- Nested flattening limited to 1 level (
Address.Cityโ ,Address.Street.Line1โ) - Collection mapping ~27% slower than AutoMapper for 100-1000 items (competitive on 10K+)
- EF Core ProjectTo works with
ForMemberexpressions, but notResolveUsingdelegates
Behavioral Differences from AutoMapper
- Circular references: Returns default value instead of throwing exception
- Null safety: More aggressive null-safe navigation (fewer NullReferenceException)
- Unmapped properties: Silent (use
GetUnmappedPropertiesfor validation) - Cache behavior: Default is unbounded (must opt-in to LRU)
Platform Support
| .NET Version | Mapsicle Support |
|---|---|
| .NET 8.0 | โ Fully supported |
| .NET 6.0-7.0 | โ Via .NET Standard 2.0 |
| .NET 5.0 | โ Via .NET Standard 2.0 |
| .NET Core 2.0+ | โ Via .NET Standard 2.0 |
| .NET Framework 4.6.1+ | โ Via .NET Standard 2.0 |
๐ API Reference
Core Extensions (using Mapsicle)
MapTo<T>(this object source)
Maps a source object to a new instance of type T.
Parameters:
source- The source object to map from
Returns:
T?- New instance of T with mapped properties, ordefault(T)if source is null or max depth exceeded
Example:
var dto = user.MapTo<UserDto>();
MapTo<T>(this IEnumerable source)
Maps a collection to a List<T>.
Parameters:
source- The source collection
Returns:
List<T>- New list with mapped items (empty if source is null)
Optimization: Pre-allocates capacity if source implements ICollection
Example:
List<UserDto> dtos = users.MapTo<UserDto>();
Map<TDest>(this object source, TDest destination)
Updates an existing destination object from source.
Parameters:
source- The source objectdestination- The destination object to update
Returns:
TDest- The updated destination (same instance)
Example:
source.Map(existingDto); // Updates existingDto in-place
ToDictionary(this object source)
Converts an object to a dictionary of property name/value pairs.
Returns:
Dictionary<string, object?>- Case-insensitive dictionary
Example:
var dict = user.ToDictionary();
MapTo<T>(this IDictionary<string, object?> source) where T : new()
Maps a dictionary to an object.
Constraints:
- T must have a parameterless constructor
Example:
var user = dict.MapTo<User>();
Static Mapper Configuration
Mapper.MaxDepth
- Type:
int - Default:
32 - Description: Maximum recursion depth before returning default value (circular reference protection)
Mapper.MaxDepth = 64;
Mapper.UseLruCache
- Type:
bool - Default:
false - Description: Enables memory-bounded LRU cache. Clears all caches when changed.
Mapper.UseLruCache = true;
Mapper.MaxCacheSize
- Type:
int - Default:
1000 - Description: Maximum cache entries when UseLruCache is enabled
Mapper.MaxCacheSize = 2000;
Mapper.Logger
- Type:
Action<string>? - Default:
null - Description: Logger for diagnostic messages (depth warnings, etc)
Mapper.Logger = msg => _logger.LogDebug(msg);
Mapper.ClearCache()
Clears all cached mapping delegates.
Mapper.ClearCache();
Mapper.CacheInfo()
- Returns:
MapperCacheInfo- Current cache statistics
var stats = Mapper.CacheInfo();
Console.WriteLine($"Total: {stats.Total}, Hit Ratio: {stats.HitRatio:P1}");
Mapper.AssertMappingValid<TSource, TDest>()
Validates mapping configuration. Throws InvalidOperationException if unmapped properties exist.
Mapper.AssertMappingValid<User, UserDto>();
Mapper.GetUnmappedProperties<TSource, TDest>()
- Returns:
List<string>- Names of destination properties that cannot be mapped
var unmapped = Mapper.GetUnmappedProperties<User, UserDto>();
MapperFactory
MapperFactory.Create(MapperOptions? options = null)
Creates an isolated mapper instance with independent cache and depth tracking.
Parameters:
options- Optional configuration (MaxDepth, Logger, UseLruCache, MaxCacheSize)
Returns:
IDisposablemapper instance
Example:
using var mapper = MapperFactory.Create(new MapperOptions
{
MaxDepth = 16,
UseLruCache = true,
MaxCacheSize = 100,
Logger = Console.WriteLine
});
var dto = mapper.MapTo<UserDto>(user);
Fluent API (using Mapsicle.Fluent)
MapperConfiguration
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<User, UserDto>()
.ForMember(d => d.FullName, opt => opt.MapFrom(s => s.FirstName + " " + s.LastName))
.ForMember(d => d.Password, opt => opt.Ignore())
.ForMember(d => d.IsActive, opt => opt.Condition(s => s.Status == "Active"))
.BeforeMap((src, dest) => Console.WriteLine("Mapping started"))
.AfterMap((src, dest) => dest.MappedAt = DateTime.UtcNow)
.Include<PowerUser, PowerUserDto>()
.ConstructUsing(src => new UserDto(src.Id))
.ReverseMap();
cfg.CreateConverter<Money, decimal>(m => m.Amount);
});
config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();
Configuration Methods
ForMember<TMember>()- Configure individual member mappingopt.MapFrom(expr)- Map from custom expressionopt.Ignore()- Don't map this memberopt.Condition(pred)- Conditional mappingopt.ResolveUsing(func)- Custom resolver function
BeforeMap(action)- Execute action before mappingAfterMap(action)- Execute action after mappingInclude<TDerived, TDest>()- Polymorphic mapping supportConstructUsing(factory)- Custom object constructionReverseMap()- Create reverse mappingCreateConverter<TSource, TDest>(converter)- Global type converter
EntityFramework Extensions (using Mapsicle.EntityFramework)
ProjectTo<TSource, TDest>(this IQueryable<TSource> query, MapperConfiguration? config = null)
Translates mapping to SQL expression (executed in database).
Parameters:
query- Source EF Core queryableconfig- Optional mapper configuration for custom mappings
Returns:
IQueryable<TDest>- Queryable projection
Example:
var dtos = await context.Users
.Where(u => u.IsActive)
.ProjectTo<User, UserDto>(config)
.ToListAsync();
๐ Complete Feature List
Core Features
- โ Zero-config convention mapping
- โ Collection mapping (List, Array, IEnumerable)
- โ Dictionary mapping (object โ Dictionary)
- โ
Flattening (
AddressCityโAddress.City) - โ
Nullable type coercion (
TโT?) - โ Enum to numeric conversion
- โ Nested object mapping
- โ Case-insensitive property matching
- โ Record type support (positional parameters)
- โ Anonymous type support
- โ Circular reference protection
- โ Thread-safe caching
Advanced Features
- โ
[MapFrom]attribute - โ
[IgnoreMap]attribute - โ Fluent configuration API
- โ ForMember custom expressions
- โ BeforeMap/AfterMap hooks
- โ
Polymorphic mapping (
.Include<>) - โ
Custom construction (
.ConstructUsing) - โ Global type converters
- โ Conditional mapping
- โ ReverseMap
- โ DI integration
- โ Configuration validation
Enterprise Features
- โ LRU cache option (memory-bounded)
- โ Cache statistics (hits, misses, ratio)
- โ PropertyInfo caching
- โ Lock-free reads
- โ Isolated mapper instances
- โ Configurable depth limits
- โ Diagnostic logging
- โ Unmapped property detection
EF Core Features
- โ ProjectTo with SQL translation
- โ ForMember in ProjectTo
- โ Flattening in SQL
- โ Nested projection
- โ Type coercion in queries
๐งช Test Coverage
| Package | Tests | Coverage |
|---|---|---|
| Mapsicle | 67 | Core + Stability |
| Mapsicle.Fluent | 18 | Fluent + Enterprise |
| Mapsicle.EntityFramework | 7 | EF Core |
| Total | 92 |
๐ Project Structure
Mapsicle/
โโโ src/
โ โโโ Mapsicle/ # Core - zero config
โ โโโ Mapsicle.Fluent/ # Fluent + DI
โ โโโ Mapsicle.EntityFramework/ # EF Core ProjectTo
โโโ tests/
โโโ Mapsicle.Tests/
โโโ Mapsicle.Fluent.Tests/
โโโ Mapsicle.EntityFramework.Tests/
โโโ Mapsicle.Benchmarks/
๐ค Contributing
PRs welcome! Areas for contribution:
- Performance optimizations
- Additional type coercion scenarios
- Documentation improvements
๐ License
MPL 2.0 License ยฉ Arnel Isiderio Robles
<p align="center"> <strong>Stop configuring. Start mapping.</strong><br> <em>Free forever. Zero dependencies. Pure performance.</em> </p>
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 was computed. 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. |
-
net8.0
- Mapsicle (>= 1.0.1)
- Mapsicle.Fluent (>= 1.0.1)
- Microsoft.EntityFrameworkCore (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.