Skip to content

Commit 6215cae

Browse files
committed
Added validation for many-to-many relationships with Inverse specified on both sides.
1 parent 7019aa0 commit 6215cae

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

src/FluentNHibernate.Specs/PersistenceModel/PersistenceModelSpecs.Validation.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using FluentNHibernate.Mapping;
34
using FluentNHibernate.Visitors;
45
using Machine.Specifications;
@@ -51,6 +52,43 @@ public class when_the_persistence_model_is_told_to_build_the_mappings_with_a_cla
5152
exception.Message.ShouldEqual("The entity 'Target' doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id).");
5253
}
5354

55+
public class when_the_persistence_model_is_told_to_build_the_mappings_with_a_many_to_many_relationship_with_inverse_specified_on_both_sides : PersistenceModelValidationSpec
56+
{
57+
Establish context = () =>
58+
{
59+
var left = new ClassMap<Left>();
60+
left.Id(x => x.Id);
61+
left.HasManyToMany(x => x.Rights)
62+
.Inverse();
63+
var right = new ClassMap<Right>();
64+
right.Id(x => x.Id);
65+
right.HasManyToMany(x => x.Lefts)
66+
.Inverse();
67+
68+
model = new FluentNHibernate.PersistenceModel();
69+
model.Add(left);
70+
model.Add(right);
71+
};
72+
73+
Because of = () =>
74+
exception = Catch.Exception(() => model.BuildMappings());
75+
76+
It should_throw_a_validation_exception = () =>
77+
{
78+
exception.ShouldNotBeNull();
79+
exception.ShouldBeOfType<ValidationException>();
80+
};
81+
82+
It should_indicate_which_entity_has_the_invalid_many_to_many = () =>
83+
exception.As<ValidationException>().RelatedEntity.ShouldEqual(typeof(Left));
84+
85+
It should_explain_how_to_correct_the_error = () =>
86+
exception.As<ValidationException>().Resolution.ShouldEqual("Remove Inverse from one side of the relationship");
87+
88+
It should_provide_a_sufficently_detailed_message_in_the_exception = () =>
89+
exception.Message.ShouldEqual("The relationship Left.Rights to Right.Lefts has Inverse specified on both sides. Remove Inverse from one side of the relationship.");
90+
}
91+
5492
public class when_the_persistence_model_with_validation_disabled_is_told_to_build_the_mappings_with_a_class_mapping_that_doesnt_have_an_id : PersistenceModelValidationSpec
5593
{
5694
Establish context = () =>
@@ -76,5 +114,17 @@ protected class Target
76114
{
77115
public int Id { get; set; }
78116
}
117+
118+
protected class Left
119+
{
120+
public int Id { get; set; }
121+
public IList<Right> Rights { get; set; }
122+
}
123+
124+
protected class Right
125+
{
126+
public int Id { get; set; }
127+
public IList<Left> Lefts { get; set; }
128+
}
79129
}
80130
}

src/FluentNHibernate/Visitors/ValidationVisitor.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using FluentNHibernate.MappingModel.ClassBased;
2+
using FluentNHibernate.MappingModel.Collections;
23

34
namespace FluentNHibernate.Visitors
45
{
@@ -23,6 +24,22 @@ public override void ProcessClass(ClassMapping classMapping)
2324
);
2425
}
2526

27+
protected override void ProcessCollection(ICollectionMapping mapping)
28+
{
29+
if (!Enabled) return;
30+
31+
var otherSide = mapping.OtherSide as ICollectionMapping;
32+
33+
if (otherSide == null) return;
34+
if (mapping.Inverse && otherSide.Inverse)
35+
{
36+
throw new ValidationException(
37+
string.Format("The relationship {0}.{1} to {2}.{3} has Inverse specified on both sides.", mapping.ContainingEntityType.Name, mapping.Name, otherSide.ContainingEntityType.Name, otherSide.Name),
38+
"Remove Inverse from one side of the relationship",
39+
mapping.ContainingEntityType);
40+
}
41+
}
42+
2643
/// <summary>
2744
/// Gets or sets whether validation is performed.
2845
/// </summary>

0 commit comments

Comments
 (0)