Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ public void ShouldNotCreateDictionaryAsFallbackComplexType()
[Fact]
public void ShouldFlattenAComplexTypeCollectionToANestedObjectDictionaryImplementation()
{
var source = new PublicField<ICollection<Customer>>()
var source = new PublicField<ICollection<Customer>>
{
Value = new[]
{
Expand Down Expand Up @@ -339,6 +339,64 @@ public void ShouldFlattenAComplexTypeCollectionToANestedObjectDictionaryImplemen

}

// See https://github.com/agileobjects/AgileMapper/issues/200
[Fact]
public void ShouldMapListDictionaries()
{
var source = new PublicField<Dictionary<string, List<string>>>
{
Value = new Dictionary<string, List<string>>
{
["a"] = new List<string> { "b" }
}
};

var result = Mapper.Map(source)
.ToANew<PublicProperty<Dictionary<string, List<string>>>>();

var resultDictionary = result
.ShouldNotBeNull()
.Value
.ShouldNotBeNull();

resultDictionary.ShouldHaveSingleItem();
resultDictionary["a"].ShouldHaveSingleItem().ShouldBe("b");
}

[Fact]
public void ShouldMapArrayDictionaries()
{
var source = new PublicField<Dictionary<string, int[]>>
{
Value = new Dictionary<string, int[]>
{
["1"] = new[] { 1 },
["2"] = new[] { 1, 2 },
["3"] = new[] { 1, 2, 3 },
}
};

var result = Mapper.Map(source)
.ToANew<PublicProperty<Dictionary<string, long[]>>>();

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
Expand Down
3 changes: 2 additions & 1 deletion AgileMapper/Caching/ArrayCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
_keys[_length] = key;
}

_values[_length++] = value;
_values[_length] = value;
_length++;
}

return value;
Expand Down
33 changes: 20 additions & 13 deletions AgileMapper/Members/Dictionaries/DictionaryEntrySourceMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -42,26 +47,28 @@ private DictionaryEntrySourceMember(
Func<string> 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<string> pathFactory,
QualifiedMember matchedTargetMember,
DictionarySourceMember parent)
{
Type = type;
_pathFactory = pathFactory;
_matchedTargetMember = matchedTargetMember;
Parent = parent;
}

public DictionarySourceMember Parent { get; }

public bool IsRoot => false;
Expand Down
7 changes: 5 additions & 2 deletions AgileMapper/Members/Dictionaries/DictionarySourceMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -94,8 +95,10 @@ private DictionarySourceMember(

public IQualifiedMember GetElementMember()
{
return EntryMember.IsEnumerable
? EntryMember.GetElementMember()
return _elementMember ??= EntryMember.IsEnumerable
? IsEntireDictionaryMatch
? EntryMember
: EntryMember.GetElementMember()
: EntryMember.GetInstanceElementMember();
}

Expand Down
2 changes: 1 addition & 1 deletion AgileMapper/Members/Sources/ElementMembersSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ QualifiedMember IMembersSource.GetTargetMember<TSource, TTarget>()
=> GetTargetMember();

public QualifiedMember GetTargetMember()
=> _targetMember ?? (_targetMember = _enumerableMapperData.TargetMember.GetElementMember());
=> _targetMember ??= _enumerableMapperData.TargetMember.GetElementMember();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
using System.Linq.Expressions;
#endif
using DataSources;
using AgileObjects.AgileMapper.Extensions.Internal;
using Extensions.Internal;
using TypeConversion;
using Members;

Expand Down
6 changes: 3 additions & 3 deletions AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
});
}

Expand Down
12 changes: 6 additions & 6 deletions docs/src/configuration/Object-Mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ Configure a custom factory for the mapping of a particular type using:
Mapper.WhenMapping
.From<CustomerViewModel>() // Apply to CustomerViewModel mappings
.ToANew<Customer>() // 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
});
```

Expand All @@ -21,10 +21,10 @@ Configure a conditional custom factory using ([inline](/configuration/Inline) ex
```cs
Mapper.Map(customerViewModel).ToANew<Customer>(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
}));
```