Skip to content

Commit 787092f

Browse files
committed
Fix for issue #39.
1 parent c24de5a commit 787092f

File tree

5 files changed

+121
-20
lines changed

5 files changed

+121
-20
lines changed

src/FluentNHibernate.Specs/Visitors/BiDirectionalManyToManyPairingVisitorSpecs.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,36 @@ private class Queue
191191
}
192192
}
193193

194+
public class when_the_bi_directional_many_to_many_visitor_is_asked_to_pair_a_self_referential_many_to_many_relationship_when_has_two_possible_collections : BiDirectionalManyToManyPairingVisitorSpec
195+
{
196+
Establish context = () =>
197+
{
198+
ancestors = collection<TreeNode>(x => x.Ancestors);
199+
descendants = collection<TreeNode>(x => x.Descendants);
200+
};
201+
202+
Because of = () =>
203+
Visit(descendants, ancestors);
204+
205+
It should_call_the_user_defined_func = () =>
206+
udf_was_called.ShouldBeTrue();
207+
208+
It should_link_ancestors_to_descendants = () =>
209+
ancestors.OtherSide.ShouldEqual(descendants);
210+
211+
It should_link_descendants_to_ancestors = () =>
212+
descendants.OtherSide.ShouldEqual(ancestors);
213+
214+
static CollectionMapping ancestors;
215+
static CollectionMapping descendants;
216+
217+
private class TreeNode
218+
{
219+
public IEnumerable<TreeNode> Ancestors { get; set; }
220+
public IEnumerable<TreeNode> Descendants { get; set; }
221+
}
222+
}
223+
194224
public class when_the_bi_directional_many_to_many_visitor_is_asked_to_pair_two_collections_that_are_exposed_through_methods : BiDirectionalManyToManyPairingVisitorSpec
195225
{
196226
Establish context = () =>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System.Collections.Generic;
2+
using FluentNHibernate.Cfg.Db;
3+
using FluentNHibernate.Mapping;
4+
using NHibernate.Cfg;
5+
using NUnit.Framework;
6+
7+
namespace FluentNHibernate.Testing.DomainModel.Mapping
8+
{
9+
[TestFixture]
10+
public class ManyToManySelfReferencedInverseIntegrationTester
11+
{
12+
public class TreeNode
13+
{
14+
public virtual int Id { get; set; }
15+
public virtual IEnumerable<TreeNode> Ancestors { get; set; }
16+
public virtual IEnumerable<TreeNode> Descendants { get; set; }
17+
}
18+
19+
public class TreeNodeMap : ClassMap<TreeNode>
20+
{
21+
public TreeNodeMap()
22+
{
23+
Id(x => x.Id)
24+
.GeneratedBy.Native();
25+
26+
HasManyToMany(x => x.Ancestors)
27+
.AsSet()
28+
.Table("TreeNode_hierarhy")
29+
.ParentKeyColumn("ChildID")
30+
.ChildKeyColumn("ParentID")
31+
.Cascade.SaveUpdate();
32+
33+
HasManyToMany(x => x.Descendants)
34+
.AsSet()
35+
.Table("TreeNode_hierarhy")
36+
.ParentKeyColumn("ParentID")
37+
.ChildKeyColumn("ChildID")
38+
.Inverse();
39+
}
40+
}
41+
42+
private class ManyToManyPersistenceModel : PersistenceModel
43+
{
44+
public override void Configure(Configuration configuration)
45+
{
46+
Add(new TreeNodeMap());
47+
base.Configure(configuration);
48+
}
49+
}
50+
51+
[Test]
52+
public void NHibernateCanLoadOneToManyTargetMapping()
53+
{
54+
var cfg = new SQLiteConfiguration()
55+
.InMemory()
56+
.ConfigureProperties(new Configuration());
57+
58+
var model = new ManyToManyPersistenceModel();
59+
model.Configure(cfg);
60+
61+
cfg.BuildSessionFactory();
62+
}
63+
}
64+
}

src/FluentNHibernate.Testing/FluentNHibernate.Testing.csproj

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,16 @@
117117
<Compile Include="AutoMapping\Overrides\ClassMappingOverrides.cs" />
118118
<Compile Include="AutoMapping\Overrides\CompositeIdOverrides.cs" />
119119
<Compile Include="AutoMapping\Overrides\HibernateMappingOverrides.cs" />
120+
<Compile Include="DomainModel\Mapping\ManyToManySelfReferencedInverseIntegrationTester.cs" />
120121
<Compile Include="DomainModel\MemberAccessResolverTests.cs" />
121122
<Compile Include="DomainModel\MemberBackingFieldTests.cs" />
122123
<Compile Include="DomainModel\NamingTests.cs" />
123-
<Compile Include="AutoMapping\Overrides\ParentOverridesWithSubclasses.cs" />
124+
<Compile Include="AutoMapping\Overrides\ParentOverridesWithSubclasses.cs" />
124125
<Compile Include="AutoMapping\UnionSubclassConventionTests.cs" />
125-
<Compile Include="AutoMapping\UnionSubclassTests.cs" />
126+
<Compile Include="AutoMapping\UnionSubclassTests.cs" />
126127
<Compile Include="Fixtures\AutoMappingAlterations\AbstractOverride.cs" />
127128
<Compile Include="Fixtures\AutoMappingAlterations\AbstractOverrideImplementation.cs" />
128-
<Compile Include="Fixtures\AutoMappingAlterations\Model\Qux.cs" />
129+
<Compile Include="Fixtures\AutoMappingAlterations\Model\Qux.cs" />
129130
<Compile Include="Cfg\Db\IngresConfigurationTester.cs" />
130131
<Compile Include="StubTypeSource.cs" />
131132
<Compile Include="AutoMapping\TestFixtures.cs" />
@@ -483,4 +484,4 @@
483484
<Target Name="AfterBuild">
484485
</Target>
485486
-->
486-
</Project>
487+
</Project>

src/FluentNHibernate/Visitors/NullMappingModelVisitor.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using FluentNHibernate.MappingModel.ClassBased;
44
using FluentNHibernate.MappingModel.Collections;
55
using FluentNHibernate.MappingModel.Identity;
6-
using CollectionMapping = FluentNHibernate.MappingModel.Collections.CollectionMapping;
76

87
namespace FluentNHibernate.Visitors
98
{
@@ -224,7 +223,7 @@ public virtual void Visit(IIdentityMapping identityMapping)
224223

225224
}
226225

227-
public virtual void Visit(MappingModel.Collections.CollectionMapping collectionMapping)
226+
public virtual void Visit(CollectionMapping collectionMapping)
228227
{
229228

230229
}

src/FluentNHibernate/Visitors/RelationshipPairingVisitor.cs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66

77
namespace FluentNHibernate.Visitors
88
{
9-
public delegate void PairBiDirectionalManyToManySidesDelegate(MappingModel.Collections.CollectionMapping current, IEnumerable<MappingModel.Collections.CollectionMapping> possibles, bool wasResolved);
9+
public delegate void PairBiDirectionalManyToManySidesDelegate(CollectionMapping current, IEnumerable<CollectionMapping> possibles, bool wasResolved);
1010

1111
public class RelationshipPairingVisitor : DefaultMappingModelVisitor
1212
{
1313
readonly PairBiDirectionalManyToManySidesDelegate userControlledPair;
14-
readonly List<MappingModel.Collections.CollectionMapping> manyToManys = new List<MappingModel.Collections.CollectionMapping>();
15-
readonly List<MappingModel.Collections.CollectionMapping> oneToManys = new List<MappingModel.Collections.CollectionMapping>();
14+
readonly List<CollectionMapping> manyToManys = new List<CollectionMapping>();
15+
readonly List<CollectionMapping> oneToManys = new List<CollectionMapping>();
1616
readonly List<ManyToOneMapping> references = new List<ManyToOneMapping>();
1717

1818
public RelationshipPairingVisitor(PairBiDirectionalManyToManySidesDelegate userControlledPair)
@@ -41,7 +41,7 @@ public override void ProcessManyToOne(ManyToOneMapping manyToOneMapping)
4141
references.Add(manyToOneMapping);
4242
}
4343

44-
static void PairOneToManys(IEnumerable<MappingModel.Collections.CollectionMapping> collections, IEnumerable<ManyToOneMapping> refs)
44+
static void PairOneToManys(IEnumerable<CollectionMapping> collections, IEnumerable<ManyToOneMapping> refs)
4545
{
4646
var orderedCollections = collections.OrderBy(x => x.Name).ToArray();
4747
var orderedRefs = refs.OrderBy(x => x.Name).ToArray();
@@ -58,7 +58,7 @@ static void PairOneToManys(IEnumerable<MappingModel.Collections.CollectionMappin
5858
}
5959
}
6060

61-
void PairManyToManys(IEnumerable<MappingModel.Collections.CollectionMapping> rs)
61+
void PairManyToManys(IEnumerable<CollectionMapping> rs)
6262
{
6363
if (!rs.Any()) return;
6464

@@ -72,9 +72,10 @@ void PairManyToManys(IEnumerable<MappingModel.Collections.CollectionMapping> rs)
7272
// try to pair the current side with the potential other sides
7373
var mapping = current;
7474

75-
if (candidates.Count() == 1)
75+
var candidatesCount = candidates.Count();
76+
if (candidatesCount == 1)
7677
mapping = PairExactMatches(rs, current, candidates);
77-
else if (candidates.Count() > 1)
78+
else if (candidatesCount > 1)
7879
mapping = PairFuzzyMatches(rs, current, candidates);
7980

8081
if (mapping == null)
@@ -89,7 +90,7 @@ void PairManyToManys(IEnumerable<MappingModel.Collections.CollectionMapping> rs)
8990

9091
// both collections have been paired, so remove them
9192
// from the available collections
92-
PairManyToManys(rs.Except(mapping, (MappingModel.Collections.CollectionMapping)mapping.OtherSide));
93+
PairManyToManys(rs.Except(mapping, (CollectionMapping)mapping.OtherSide));
9394
}
9495

9596
static string GetMemberName(Member member)
@@ -100,7 +101,7 @@ static string GetMemberName(Member member)
100101
return member.Name;
101102
}
102103

103-
static LikenessContainer GetLikeness(MappingModel.Collections.CollectionMapping currentMapping, MappingModel.Collections.CollectionMapping mapping)
104+
static LikenessContainer GetLikeness(CollectionMapping currentMapping, CollectionMapping mapping)
104105
{
105106
var currentMemberName = GetMemberName(currentMapping.Member);
106107
var mappingMemberName = GetMemberName(mapping.Member);
@@ -114,18 +115,23 @@ static LikenessContainer GetLikeness(MappingModel.Collections.CollectionMapping
114115
};
115116
}
116117

117-
static bool both_collections_point_to_each_others_types(MappingModel.Collections.CollectionMapping left, MappingModel.Collections.CollectionMapping right)
118+
static bool both_collections_point_to_each_others_types(CollectionMapping left, CollectionMapping right)
118119
{
119120
return left.ContainingEntityType == right.ChildType &&
120121
left.ChildType == right.ContainingEntityType;
121122
}
122123

124+
static bool self_referenced_relation_does_not_point_to_itself(CollectionMapping left, CollectionMapping right)
125+
{
126+
return left.ChildType == left.ContainingEntityType && right.ChildType == right.ContainingEntityType && left != right;
127+
}
128+
123129
static bool likeness_within_threshold(LikenessContainer current)
124130
{
125131
return current.Differences != current.CurrentMemberName.Length;
126132
}
127133

128-
static MappingModel.Collections.CollectionMapping PairFuzzyMatches(IEnumerable<MappingModel.Collections.CollectionMapping> rs, MappingModel.Collections.CollectionMapping current, IEnumerable<MappingModel.Collections.CollectionMapping> potentialOtherSides)
134+
static CollectionMapping PairFuzzyMatches(IEnumerable<CollectionMapping> rs, CollectionMapping current, IEnumerable<CollectionMapping> potentialOtherSides)
129135
{
130136
// no exact matches found, drop down to a levenshtein distance
131137
var mapping = current;
@@ -157,7 +163,7 @@ static MappingModel.Collections.CollectionMapping PairFuzzyMatches(IEnumerable<M
157163
return mapping;
158164
}
159165

160-
static MappingModel.Collections.CollectionMapping PairExactMatches(IEnumerable<MappingModel.Collections.CollectionMapping> rs, MappingModel.Collections.CollectionMapping current, IEnumerable<MappingModel.Collections.CollectionMapping> potentialOtherSides)
166+
static CollectionMapping PairExactMatches(IEnumerable<CollectionMapping> rs, CollectionMapping current, IEnumerable<CollectionMapping> potentialOtherSides)
161167
{
162168
var otherSide = potentialOtherSides.Single();
163169

@@ -172,9 +178,10 @@ static MappingModel.Collections.CollectionMapping PairExactMatches(IEnumerable<M
172178
return mapping;
173179
}
174180

175-
static MappingModel.Collections.CollectionMapping FindAlternative(IEnumerable<MappingModel.Collections.CollectionMapping> rs, MappingModel.Collections.CollectionMapping current, MappingModel.Collections.CollectionMapping otherSide)
181+
static CollectionMapping FindAlternative(IEnumerable<CollectionMapping> rs, CollectionMapping current, CollectionMapping otherSide)
176182
{
177183
var alternative = rs
184+
.Where(x => self_referenced_relation_does_not_point_to_itself(x, current))
178185
.Where(x => x.ContainingEntityType == current.ContainingEntityType)
179186
.Select(x => GetLikeness(x, otherSide))
180187
.OrderBy(x => x.Differences)
@@ -195,7 +202,7 @@ static bool AnyHaveSameLikeness(IEnumerable<LikenessContainer> likenesses, Liken
195202

196203
class LikenessContainer
197204
{
198-
public MappingModel.Collections.CollectionMapping Collection { get; set; }
205+
public CollectionMapping Collection { get; set; }
199206
public string CurrentMemberName { get; set; }
200207
public string MappingMemberName { get; set; }
201208
public int Differences { get; set; }

0 commit comments

Comments
 (0)