diff --git a/AgileMapper.PerformanceTester.Net461/AgileMapper.PerformanceTester.Net461.csproj b/AgileMapper.PerformanceTester.Net461/AgileMapper.PerformanceTester.Net461.csproj
index 1b2c38431..587322d49 100644
--- a/AgileMapper.PerformanceTester.Net461/AgileMapper.PerformanceTester.Net461.csproj
+++ b/AgileMapper.PerformanceTester.Net461/AgileMapper.PerformanceTester.Net461.csproj
@@ -37,8 +37,8 @@
..\packages\AgileObjects.NetStandardPolyfills.1.4.1\lib\net40\AgileObjects.NetStandardPolyfills.dll
-
- ..\packages\AgileObjects.ReadableExpressions.2.5.0\lib\net40\AgileObjects.ReadableExpressions.dll
+
+ ..\packages\AgileObjects.ReadableExpressions.2.5.1\lib\net40\AgileObjects.ReadableExpressions.dll
..\packages\AutoMapper.7.0.1\lib\net45\AutoMapper.dll
diff --git a/AgileMapper.PerformanceTester.Net461/packages.config b/AgileMapper.PerformanceTester.Net461/packages.config
index e8b2821c2..6c40706b4 100644
--- a/AgileMapper.PerformanceTester.Net461/packages.config
+++ b/AgileMapper.PerformanceTester.Net461/packages.config
@@ -1,7 +1,7 @@
-
+
diff --git a/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj b/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj
index 8c0e81871..b7e78114d 100644
--- a/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj
+++ b/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj
@@ -39,7 +39,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/AgileMapper.UnitTests.NetCore/AgileMapper.UnitTests.NetCore.csproj b/AgileMapper.UnitTests.NetCore/AgileMapper.UnitTests.NetCore.csproj
index 97252c0a1..999b8acf1 100644
--- a/AgileMapper.UnitTests.NetCore/AgileMapper.UnitTests.NetCore.csproj
+++ b/AgileMapper.UnitTests.NetCore/AgileMapper.UnitTests.NetCore.csproj
@@ -36,7 +36,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests.NetCore2.1/AgileMapper.UnitTests.NetCore2.1.csproj b/AgileMapper.UnitTests.NetCore2.1/AgileMapper.UnitTests.NetCore2.1.csproj
index 67e922d6b..3e40f1f61 100644
--- a/AgileMapper.UnitTests.NetCore2.1/AgileMapper.UnitTests.NetCore2.1.csproj
+++ b/AgileMapper.UnitTests.NetCore2.1/AgileMapper.UnitTests.NetCore2.1.csproj
@@ -37,7 +37,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests.NetCore2.2/AgileMapper.UnitTests.NetCore2.2.csproj b/AgileMapper.UnitTests.NetCore2.2/AgileMapper.UnitTests.NetCore2.2.csproj
index 663495ce2..5e0d1efe0 100644
--- a/AgileMapper.UnitTests.NetCore2.2/AgileMapper.UnitTests.NetCore2.2.csproj
+++ b/AgileMapper.UnitTests.NetCore2.2/AgileMapper.UnitTests.NetCore2.2.csproj
@@ -37,7 +37,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests.NetCore3.1/AgileMapper.UnitTests.NetCore3.1.csproj b/AgileMapper.UnitTests.NetCore3.1/AgileMapper.UnitTests.NetCore3.1.csproj
index 38f8dc622..81cfab425 100644
--- a/AgileMapper.UnitTests.NetCore3.1/AgileMapper.UnitTests.NetCore3.1.csproj
+++ b/AgileMapper.UnitTests.NetCore3.1/AgileMapper.UnitTests.NetCore3.1.csproj
@@ -37,7 +37,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests.NetCore3/AgileMapper.UnitTests.NetCore3.csproj b/AgileMapper.UnitTests.NetCore3/AgileMapper.UnitTests.NetCore3.csproj
index 0534875b8..44543edab 100644
--- a/AgileMapper.UnitTests.NetCore3/AgileMapper.UnitTests.NetCore3.csproj
+++ b/AgileMapper.UnitTests.NetCore3/AgileMapper.UnitTests.NetCore3.csproj
@@ -37,7 +37,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj b/AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj
index c9f7ca6e8..b6a183796 100644
--- a/AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj
+++ b/AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj
@@ -26,7 +26,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests.Orms.Ef5.LocalDb/AgileMapper.UnitTests.Orms.Ef5.LocalDb.csproj b/AgileMapper.UnitTests.Orms.Ef5.LocalDb/AgileMapper.UnitTests.Orms.Ef5.LocalDb.csproj
index 014d2c0c4..63d168c2a 100644
--- a/AgileMapper.UnitTests.Orms.Ef5.LocalDb/AgileMapper.UnitTests.Orms.Ef5.LocalDb.csproj
+++ b/AgileMapper.UnitTests.Orms.Ef5.LocalDb/AgileMapper.UnitTests.Orms.Ef5.LocalDb.csproj
@@ -26,7 +26,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests.Orms.Ef5/AgileMapper.UnitTests.Orms.Ef5.csproj b/AgileMapper.UnitTests.Orms.Ef5/AgileMapper.UnitTests.Orms.Ef5.csproj
index 4c6712872..0688b7074 100644
--- a/AgileMapper.UnitTests.Orms.Ef5/AgileMapper.UnitTests.Orms.Ef5.csproj
+++ b/AgileMapper.UnitTests.Orms.Ef5/AgileMapper.UnitTests.Orms.Ef5.csproj
@@ -27,7 +27,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests.Orms.Ef6.LocalDb/AgileMapper.UnitTests.Orms.Ef6.LocalDb.csproj b/AgileMapper.UnitTests.Orms.Ef6.LocalDb/AgileMapper.UnitTests.Orms.Ef6.LocalDb.csproj
index b8b54c380..f4090b86f 100644
--- a/AgileMapper.UnitTests.Orms.Ef6.LocalDb/AgileMapper.UnitTests.Orms.Ef6.LocalDb.csproj
+++ b/AgileMapper.UnitTests.Orms.Ef6.LocalDb/AgileMapper.UnitTests.Orms.Ef6.LocalDb.csproj
@@ -26,7 +26,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests.Orms.Ef6/AgileMapper.UnitTests.Orms.Ef6.csproj b/AgileMapper.UnitTests.Orms.Ef6/AgileMapper.UnitTests.Orms.Ef6.csproj
index 86f60cd8b..08a5ec14f 100644
--- a/AgileMapper.UnitTests.Orms.Ef6/AgileMapper.UnitTests.Orms.Ef6.csproj
+++ b/AgileMapper.UnitTests.Orms.Ef6/AgileMapper.UnitTests.Orms.Ef6.csproj
@@ -27,7 +27,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests.Orms.EfCore1/AgileMapper.UnitTests.Orms.EfCore1.csproj b/AgileMapper.UnitTests.Orms.EfCore1/AgileMapper.UnitTests.Orms.EfCore1.csproj
index d1dc60466..eac0b8a9f 100644
--- a/AgileMapper.UnitTests.Orms.EfCore1/AgileMapper.UnitTests.Orms.EfCore1.csproj
+++ b/AgileMapper.UnitTests.Orms.EfCore1/AgileMapper.UnitTests.Orms.EfCore1.csproj
@@ -26,7 +26,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests.Orms.EfCore2/AgileMapper.UnitTests.Orms.EfCore2.csproj b/AgileMapper.UnitTests.Orms.EfCore2/AgileMapper.UnitTests.Orms.EfCore2.csproj
index 870a221cf..ed7fbd7d8 100644
--- a/AgileMapper.UnitTests.Orms.EfCore2/AgileMapper.UnitTests.Orms.EfCore2.csproj
+++ b/AgileMapper.UnitTests.Orms.EfCore2/AgileMapper.UnitTests.Orms.EfCore2.csproj
@@ -28,7 +28,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj b/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
index 36d350f11..98765bf2c 100644
--- a/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
+++ b/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj
@@ -31,7 +31,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingToNewDictionaryMembers.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingToNewDictionaryMembers.cs
index 9d7062577..57cbe0dad 100644
--- a/AgileMapper.UnitTests/Dictionaries/WhenMappingToNewDictionaryMembers.cs
+++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingToNewDictionaryMembers.cs
@@ -290,7 +290,7 @@ public void ShouldNotCreateDictionaryAsFallbackComplexType()
[Fact]
public void ShouldFlattenAComplexTypeCollectionToANestedObjectDictionaryImplementation()
{
- var source = new PublicField>()
+ var source = new PublicField>
{
Value = new[]
{
@@ -339,6 +339,64 @@ public void ShouldFlattenAComplexTypeCollectionToANestedObjectDictionaryImplemen
}
+ // See https://github.com/agileobjects/AgileMapper/issues/200
+ [Fact]
+ public void ShouldMapListDictionaries()
+ {
+ var source = new PublicField>>
+ {
+ Value = new Dictionary>
+ {
+ ["a"] = new List { "b" }
+ }
+ };
+
+ var result = Mapper.Map(source)
+ .ToANew>>>();
+
+ var resultDictionary = result
+ .ShouldNotBeNull()
+ .Value
+ .ShouldNotBeNull();
+
+ resultDictionary.ShouldHaveSingleItem();
+ resultDictionary["a"].ShouldHaveSingleItem().ShouldBe("b");
+ }
+
+ [Fact]
+ public void ShouldMapArrayDictionaries()
+ {
+ var source = new PublicField>
+ {
+ Value = new Dictionary
+ {
+ ["1"] = new[] { 1 },
+ ["2"] = new[] { 1, 2 },
+ ["3"] = new[] { 1, 2, 3 },
+ }
+ };
+
+ var result = Mapper.Map(source)
+ .ToANew>>();
+
+ var resultDictionary = result
+ .ShouldNotBeNull()
+ .Value
+ .ShouldNotBeNull();
+
+ resultDictionary.Count.ShouldBe(3); ;
+ resultDictionary["1"].ShouldHaveSingleItem().ShouldBe(1L);
+
+ resultDictionary["2"].Length.ShouldBe(2);
+ resultDictionary["2"][0].ShouldBe(1L);
+ resultDictionary["2"][1].ShouldBe(2L);
+
+ resultDictionary["3"].Length.ShouldBe(3);
+ resultDictionary["3"][0].ShouldBe(1L);
+ resultDictionary["3"][1].ShouldBe(2L);
+ resultDictionary["3"][2].ShouldBe(3L);
+ }
+
#region Helper Members
private static class Issue97
diff --git a/AgileMapper/AgileMapper.csproj b/AgileMapper/AgileMapper.csproj
index cb1ec3784..1e143265b 100644
--- a/AgileMapper/AgileMapper.csproj
+++ b/AgileMapper/AgileMapper.csproj
@@ -13,24 +13,15 @@
AgileObjects.AgileMapper
AgileMapper
- A zero-configuration, highly-configurable object-object mapper with viewable execution plans. Projects queries, transforms, deep clones, updates and merges via extension methods, or a static or instance API. Targets .NET Standard 1.0+ and .NET 3.5+
+ A zero-configuration, highly-configurable, unopinionated object mapper with viewable execution plans. Flattens, unflattens, deep clones, merges, updates and projects queries. Targets .NET 3.5+ and .NET Standard 1.0+
Mapper, Mapping, Mappings, ViewModel, DTO, NetStandard
https://github.com/AgileObjects/AgileMapper
1.6.1
$(PackageTargetFallback);dnxcore50
MIT
./Icon.png
- - Support for configuring complete sub-mappings, re: #176
-- Support for configuring sequential data sources, re: #184
-- Support for configuring alternate data sources, re: #133, #173
-- Including ToTarget data sources in mapping plan validation, re: #184
-- Fixing enumerable target ToTarget data sources, re: #173
-- Fixing caching of custom method struct creation factory
-- Erroring if configured data sources conflict with ignored source members
-- Improving configuration error messages
-- Surfacing mapping plan Expressions
-- Updating to ReadableExpressions v2.5
-- Performance improvements
+ - Fixing Dictionary-of-collections mapping, re: #200
+- Updating to ReadableExpressions v2.5.1
@@ -44,7 +35,7 @@
-
+
diff --git a/AgileMapper/Caching/ArrayCache.cs b/AgileMapper/Caching/ArrayCache.cs
index 8fdb577e4..e68f66d4d 100644
--- a/AgileMapper/Caching/ArrayCache.cs
+++ b/AgileMapper/Caching/ArrayCache.cs
@@ -79,7 +79,8 @@ public TValue GetOrAdd(TKey key, Func valueFactory)
_keys[_length] = key;
}
- _values[_length++] = value;
+ _values[_length] = value;
+ _length++;
}
return value;
diff --git a/AgileMapper/Members/Dictionaries/DictionaryEntrySourceMember.cs b/AgileMapper/Members/Dictionaries/DictionaryEntrySourceMember.cs
index 66ad8f65e..dd2e92923 100644
--- a/AgileMapper/Members/Dictionaries/DictionaryEntrySourceMember.cs
+++ b/AgileMapper/Members/Dictionaries/DictionaryEntrySourceMember.cs
@@ -25,6 +25,11 @@ public DictionaryEntrySourceMember(
matchedTargetMember,
parent)
{
+ var entryMember = Member.RootSource(entryType);
+ _childMembers = new[] { entryMember };
+
+ IsEnumerable = entryMember.IsEnumerable;
+ IsSimple = !IsEnumerable && entryMember.IsSimple;
}
private DictionaryEntrySourceMember(DictionaryEntrySourceMember parent, Member childMember)
@@ -42,26 +47,28 @@ private DictionaryEntrySourceMember(
Func pathFactory,
QualifiedMember matchedTargetMember,
DictionarySourceMember parent,
- Member[] childMembers = null)
+ Member[] childMembers)
+ : this(type, pathFactory, matchedTargetMember, parent)
{
- Type = type;
- _pathFactory = pathFactory;
- _matchedTargetMember = matchedTargetMember;
- Parent = parent;
- _childMembers = childMembers ?? new[] { Member.RootSource(type) };
-
- if (childMembers == null)
- {
- IsEnumerable = _childMembers.First().IsEnumerable;
- IsSimple = !IsEnumerable && _childMembers.First().IsSimple;
- return;
- }
+ _childMembers = childMembers;
var leafMember = childMembers.Last();
IsEnumerable = leafMember.IsEnumerable;
IsSimple = leafMember.IsSimple;
}
+ private DictionaryEntrySourceMember(
+ Type type,
+ Func pathFactory,
+ QualifiedMember matchedTargetMember,
+ DictionarySourceMember parent)
+ {
+ Type = type;
+ _pathFactory = pathFactory;
+ _matchedTargetMember = matchedTargetMember;
+ Parent = parent;
+ }
+
public DictionarySourceMember Parent { get; }
public bool IsRoot => false;
diff --git a/AgileMapper/Members/Dictionaries/DictionarySourceMember.cs b/AgileMapper/Members/Dictionaries/DictionarySourceMember.cs
index 34eed4ae1..fade28fa2 100644
--- a/AgileMapper/Members/Dictionaries/DictionarySourceMember.cs
+++ b/AgileMapper/Members/Dictionaries/DictionarySourceMember.cs
@@ -12,6 +12,7 @@ internal class DictionarySourceMember : IQualifiedMember
{
private readonly IQualifiedMember _wrappedSourceMember;
private readonly QualifiedMember _matchedTargetMember;
+ private IQualifiedMember _elementMember;
public DictionarySourceMember(IQualifiedMemberContext context)
: this(context.SourceMember, context.TargetMember)
@@ -94,8 +95,10 @@ private DictionarySourceMember(
public IQualifiedMember GetElementMember()
{
- return EntryMember.IsEnumerable
- ? EntryMember.GetElementMember()
+ return _elementMember ??= EntryMember.IsEnumerable
+ ? IsEntireDictionaryMatch
+ ? EntryMember
+ : EntryMember.GetElementMember()
: EntryMember.GetInstanceElementMember();
}
diff --git a/AgileMapper/Members/Sources/ElementMembersSource.cs b/AgileMapper/Members/Sources/ElementMembersSource.cs
index 9fa19efd1..bcd687a6a 100644
--- a/AgileMapper/Members/Sources/ElementMembersSource.cs
+++ b/AgileMapper/Members/Sources/ElementMembersSource.cs
@@ -34,6 +34,6 @@ QualifiedMember IMembersSource.GetTargetMember()
=> GetTargetMember();
public QualifiedMember GetTargetMember()
- => _targetMember ?? (_targetMember = _enumerableMapperData.TargetMember.GetElementMember());
+ => _targetMember ??= _enumerableMapperData.TargetMember.GetElementMember();
}
}
\ No newline at end of file
diff --git a/AgileMapper/ObjectPopulation/Enumerables/Looping/PopulationLoopDataExtensions.cs b/AgileMapper/ObjectPopulation/Enumerables/Looping/PopulationLoopDataExtensions.cs
index 0629e7386..55ed264a1 100644
--- a/AgileMapper/ObjectPopulation/Enumerables/Looping/PopulationLoopDataExtensions.cs
+++ b/AgileMapper/ObjectPopulation/Enumerables/Looping/PopulationLoopDataExtensions.cs
@@ -7,7 +7,7 @@
using System.Linq.Expressions;
#endif
using DataSources;
- using AgileObjects.AgileMapper.Extensions.Internal;
+ using Extensions.Internal;
using TypeConversion;
using Members;
diff --git a/AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs b/AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs
index 9fb0b8983..eee848757 100644
--- a/AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs
+++ b/AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs
@@ -170,10 +170,10 @@ private void AddPopulationsAndCallbacks(MappingCreationContext context)
{
AddPopulationsAndCallbacks(this, context, (factory, ctx) =>
{
- factory.AddObjectPopulation(context);
+ factory.AddObjectPopulation(ctx);
- context.MappingExpressions.AddRange(
- GetConfiguredToTargetDataSourceMappings(context, sequential: true));
+ ctx.MappingExpressions.AddRange(
+ GetConfiguredToTargetDataSourceMappings(ctx, sequential: true));
});
}
diff --git a/Directory.Build.props b/Directory.Build.props
index 5a56b9539..f2e031791 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -11,9 +11,9 @@
true
git
https://github.com/AgileObjects/AgileMapper
- 1.7.0
- 1.7.0.0
- 1.7.0.0
+ 1.7.1
+ 1.7.1.0
+ 1.7.1.0
\ No newline at end of file
diff --git a/NuGet/AgileObjects.AgileMapper.1.7.1.nupkg b/NuGet/AgileObjects.AgileMapper.1.7.1.nupkg
new file mode 100644
index 000000000..33b920e0a
Binary files /dev/null and b/NuGet/AgileObjects.AgileMapper.1.7.1.nupkg differ
diff --git a/docs/src/configuration/Object-Mapping.md b/docs/src/configuration/Object-Mapping.md
index dc63bae31..05c638f9b 100644
--- a/docs/src/configuration/Object-Mapping.md
+++ b/docs/src/configuration/Object-Mapping.md
@@ -9,10 +9,10 @@ Configure a custom factory for the mapping of a particular type using:
Mapper.WhenMapping
.From() // Apply to CustomerViewModel mappings
.ToANew() // Apply to Customer creations
- .MapInstancesUsing((cvm, c) => new Customer
+ .MapInstancesUsing(ctx => new Customer
{
- Name = cvm.Forename + " " + cvm.Surname,
- Number = cvm.CustomerNo
+ Name = ctx.Source.Forename + " " + ctx.Source.Surname,
+ Number = ctx.Source.CustomerNo
});
```
@@ -21,10 +21,10 @@ Configure a conditional custom factory using ([inline](/configuration/Inline) ex
```cs
Mapper.Map(customerViewModel).ToANew(cfg => cfg
.If((cvm, c) => cvm.Discount > 0) // Apply if view model Discount > 0
- .MapInstancesUsing((cvm, c, i) => new Customer
+ .MapInstancesUsing(ctx => new Customer
{
- Name = cvm.Forename + " " + cvm.Surname,
- Number = i,
+ Name = ctx.Source.Forename + " " + ctx.Source.Surname,
+ Number = ctx.ElementIndex,
HasDiscount = true
}));
```
\ No newline at end of file