Skip to content

Commit 7af5fe7

Browse files
committed
Improving 'exact' member matching, fixes issue #63
1 parent 2030dda commit 7af5fe7

File tree

3 files changed

+132
-26
lines changed

3 files changed

+132
-26
lines changed

AgileMapper.UnitTests/WhenMappingCircularReferences.cs

Lines changed: 113 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -395,19 +395,19 @@ public void ShouldMapNestedMultiplyRecursiveRelationships()
395395
[Fact]
396396
public void ShouldMapChildOneToManyRecursiveRelationships()
397397
{
398-
var sourceLocation1 = new Location { Id = 1 };
399-
var sourceLocation2 = new Location { Id = 2 };
398+
var sourceLocation1 = new Issue62.Location { Id = 1 };
399+
var sourceLocation2 = new Issue62.Location { Id = 2 };
400400

401-
sourceLocation1.LocationPlace = sourceLocation2.LocationPlace = new Place
401+
sourceLocation1.LocationPlace = sourceLocation2.LocationPlace = new Issue62.Place
402402
{
403403
Locations = new[] { sourceLocation1, sourceLocation2 }
404404
};
405405

406-
var source = new[] { sourceLocation1, sourceLocation2 };
406+
IEnumerable<Issue62.Location> source = new[] { sourceLocation1, sourceLocation2 };
407407

408408
var result = Mapper
409-
.Map<IEnumerable<Location>>(source)
410-
.ToANew<IEnumerable<DtoLocation>>()
409+
.Map(source)
410+
.ToANew<IEnumerable<Issue62.DtoLocation>>()
411411
.ToArray();
412412

413413
result.Length.ShouldBe(2);
@@ -427,6 +427,44 @@ public void ShouldMapChildOneToManyRecursiveRelationships()
427427
dtoLocation2.LocationPlace.Locations.Second().ShouldBe(dtoLocation2);
428428
}
429429

430+
[Fact]
431+
public void ShouldMatchConfiguredSourceEnumerablesInRecursiveRelationships()
432+
{
433+
using (var mapper = Mapper.CreateNew())
434+
{
435+
mapper
436+
.GetPlanFor<IEnumerable<Issue63.Location>>()
437+
.ToANew<IEnumerable<Issue63.DtoLocation>>(cfg => cfg
438+
.WhenMapping
439+
.From<Issue63.Place>()
440+
.To<Issue63.DtoPlace>()
441+
.Map((p, dto) => p.PlaceLabels.Select(x => x.Label))
442+
.To(dto => dto.Labels));
443+
444+
mapper
445+
.GetPlanFor<Issue63.Location>()
446+
.ToANew<Issue63.DtoLocation>();
447+
448+
var sourceLocation = new Issue63.Location { Id = 1 };
449+
var sourcePlace = new Issue63.Place();
450+
var sourceLabel = new Issue63.Label { Id = 1, Name = "Mr Label" };
451+
var sourcePlaceLabel = new Issue63.PlaceLabel { Place = sourcePlace, Label = sourceLabel };
452+
453+
sourceLocation.Place = sourcePlace;
454+
sourcePlace.PlaceLabels = new[] { sourcePlaceLabel };
455+
sourcePlace.Locations = new[] { sourceLocation };
456+
457+
var source = new[] { sourceLocation };
458+
459+
var result = mapper
460+
.Map<IEnumerable<Issue63.Location>>(source)
461+
.ToANew<IEnumerable<Issue63.DtoLocation>>()
462+
.ToArray();
463+
464+
result.Length.ShouldBe(1);
465+
}
466+
}
467+
430468
[Fact]
431469
public void ShouldUseConfiguredRecursiveDataSources()
432470
{
@@ -583,28 +621,83 @@ internal class SubjectPresenter
583621
public Presenter Presenter { get; set; }
584622
}
585623

586-
public class Location
624+
public class Issue62
587625
{
588-
public int Id { get; set; }
626+
public class Location
627+
{
628+
public int Id { get; set; }
589629

590-
public Place LocationPlace { get; set; }
591-
}
630+
public Place LocationPlace { get; set; }
631+
}
592632

593-
public class Place
594-
{
595-
public IEnumerable<Location> Locations { get; set; }
596-
}
633+
public class Place
634+
{
635+
public IEnumerable<Location> Locations { get; set; }
636+
}
597637

598-
public class DtoLocation
599-
{
600-
public int Id { get; set; }
638+
public class DtoLocation
639+
{
640+
public int Id { get; set; }
601641

602-
public DtoPlace LocationPlace { get; set; }
642+
public DtoPlace LocationPlace { get; set; }
643+
}
644+
645+
public class DtoPlace
646+
{
647+
public IEnumerable<DtoLocation> Locations { get; set; }
648+
}
603649
}
604650

605-
public class DtoPlace
651+
public class Issue63
606652
{
607-
public IEnumerable<DtoLocation> Locations { get; set; }
653+
public class Location
654+
{
655+
public int Id { get; set; }
656+
657+
public Place Place { get; set; }
658+
}
659+
public class Place
660+
{
661+
public IEnumerable<PlaceLabel> PlaceLabels { get; set; }
662+
663+
public IEnumerable<Location> Locations { get; set; }
664+
}
665+
666+
public class PlaceLabel
667+
{
668+
public virtual Label Label { get; set; }
669+
670+
public virtual Place Place { get; set; }
671+
}
672+
673+
public class Label
674+
{
675+
public int Id { get; set; }
676+
677+
public string Name { get; set; }
678+
}
679+
680+
public class DtoLocation
681+
{
682+
public int Id { get; set; }
683+
684+
// ReSharper disable once MemberHidesStaticFromOuterClass
685+
public DtoPlace Place { get; set; }
686+
}
687+
688+
public class DtoPlace
689+
{
690+
public IEnumerable<DtoLabel> Labels { get; set; }
691+
692+
public IEnumerable<DtoLocation> Locations { get; set; }
693+
}
694+
695+
public class DtoLabel
696+
{
697+
public int Id { get; set; }
698+
699+
public string Name { get; set; }
700+
}
608701
}
609702

610703
#endregion

AgileMapper/Members/SourceMemberMatcher.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,7 @@ private static bool ExactMatchingSourceMemberExists(
8383
var sourceMember = QuerySourceMembers(
8484
parentSourceMember,
8585
targetData,
86-
(m, data) => data.MapperData.TargetMember.LeafMember.Equals(m) ||
87-
data.MapperData.TargetMember.JoinedNames.Match(new[] { m.Name }))
86+
MembersMatch)
8887
.FirstOrDefault();
8988

9089
if ((sourceMember == null) || !TypesAreCompatible(sourceMember.Type, targetData.MapperData))
@@ -97,16 +96,30 @@ private static bool ExactMatchingSourceMemberExists(
9796
return true;
9897
}
9998

99+
private static bool MembersMatch(IChildMemberMappingData mappingData, Member sourceMember)
100+
{
101+
if (mappingData.MapperData.TargetMember.LeafMember.Equals(sourceMember))
102+
{
103+
return true;
104+
}
105+
106+
return mappingData
107+
.MapperData
108+
.SourceMember
109+
.Append(sourceMember)
110+
.Matches(mappingData.MapperData.TargetMember);
111+
}
112+
100113
private static IEnumerable<Member> QuerySourceMembers(
101114
IQualifiedMember parentMember,
102115
IChildMemberMappingData mappingData,
103-
Func<Member, IChildMemberMappingData, bool> filter)
116+
Func<IChildMemberMappingData, Member, bool> filter)
104117
{
105118
var members = GlobalContext
106119
.Instance
107120
.MemberCache
108121
.GetSourceMembers(parentMember.Type)
109-
.Where(m => filter.Invoke(m, mappingData));
122+
.Where(m => filter.Invoke(mappingData, m));
110123

111124
return mappingData.RuleSet.Settings.AllowGetMethods
112125
? members
@@ -170,7 +183,7 @@ private static IEnumerable<IQualifiedMember> EnumerateSourceMembers(
170183
}
171184
}
172185

173-
private static bool MembersHaveCompatibleTypes(Member sourceMember, IChildMemberMappingData rootData)
186+
private static bool MembersHaveCompatibleTypes(IChildMemberMappingData rootData, Member sourceMember)
174187
{
175188
if (!sourceMember.IsSimple)
176189
{

LICENCE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2016 AgileObjects Ltd
3+
Copyright (c) 2018 AgileObjects Ltd
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

0 commit comments

Comments
 (0)