diff --git a/src/NHibernate.Validator.Tests/Base/Address.cs b/src/NHibernate.Validator.Tests/Base/Address.cs
index 176386f..e02ae1f 100644
--- a/src/NHibernate.Validator.Tests/Base/Address.cs
+++ b/src/NHibernate.Validator.Tests/Base/Address.cs
@@ -60,6 +60,8 @@ public string Zip
set { zip = value; }
}
+ [Length(Max = 1000, Tags = "T1")]
+ [Length(Max = 2000, Tags = "T2")]
public string Line2
{
get { return line2; }
@@ -130,4 +132,4 @@ public AddressDef()
Define(x => x.AddressFlags).Enum();
}
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Validator.Tests/Integration/HibernateAnnotationIntegrationFixture.cs b/src/NHibernate.Validator.Tests/Integration/HibernateAnnotationIntegrationFixture.cs
index 981078e..0b4de53 100644
--- a/src/NHibernate.Validator.Tests/Integration/HibernateAnnotationIntegrationFixture.cs
+++ b/src/NHibernate.Validator.Tests/Integration/HibernateAnnotationIntegrationFixture.cs
@@ -152,6 +152,19 @@ public void ApplyOnEnumColumn()
Assert.That(serialColumn.CheckConstraint, Is.Null.Or.Empty, "Validator annotation should not generate check for [Flag]ed Enums");
}
+ [Test]
+ public void SameAttributeWithDifferentTagsOnPropertyDoNotModifyNhibMappings()
+ {
+ PersistentClass classMapping = cfg.GetClassMapping(typeof(Address));
+ IEnumerator ie = classMapping.GetProperty("Line2").ColumnIterator.GetEnumerator();
+ ie.MoveNext();
+ Column serialColumn = (Column) ie.Current;
+
+
+ Assert.AreEqual(serialColumn.Length, 255, "Same attribute with different tags must not change Nhib mappings");
+ }
+
+
///
/// Test pre-update/save events and custom interpolator
///
diff --git a/src/NHibernate.Validator.Tests/Mappings/MixAddress.cs b/src/NHibernate.Validator.Tests/Mappings/MixAddress.cs
index 766a4cc..efe817b 100644
--- a/src/NHibernate.Validator.Tests/Mappings/MixAddress.cs
+++ b/src/NHibernate.Validator.Tests/Mappings/MixAddress.cs
@@ -67,5 +67,12 @@ public bool InternalValid
get { return internalValid; }
set { internalValid = value; }
}
+
+
+ [Min(1, Tags = "T1")] //This attribute will be redefined in xml mapping
+ [Min(1000, Tags = "T2")]
+ [Min(333, Tags = "T3")] //And this also will be redefined by xml
+ public int Num { get; set; }
+
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Validator.Tests/Mappings/MixAddress.nhv.xml b/src/NHibernate.Validator.Tests/Mappings/MixAddress.nhv.xml
index ab0f1bf..0bae04e 100644
--- a/src/NHibernate.Validator.Tests/Mappings/MixAddress.nhv.xml
+++ b/src/NHibernate.Validator.Tests/Mappings/MixAddress.nhv.xml
@@ -33,5 +33,9 @@
+
+
+
+
-
\ No newline at end of file
+
diff --git a/src/NHibernate.Validator.Tests/Mappings/MixedClassMappingFixture.cs b/src/NHibernate.Validator.Tests/Mappings/MixedClassMappingFixture.cs
index bd420dd..b94dd50 100644
--- a/src/NHibernate.Validator.Tests/Mappings/MixedClassMappingFixture.cs
+++ b/src/NHibernate.Validator.Tests/Mappings/MixedClassMappingFixture.cs
@@ -3,8 +3,10 @@
using System.Reflection;
using NHibernate.Validator.Cfg;
using NHibernate.Validator.Cfg.MappingSchema;
+using NHibernate.Validator.Constraints;
using NHibernate.Validator.Mappings;
using NUnit.Framework;
+using SharpTestsEx;
using RangeAttribute=NHibernate.Validator.Constraints.RangeAttribute;
namespace NHibernate.Validator.Tests.Mappings
@@ -95,6 +97,18 @@ public void MemberAttributes()
Assert.AreEqual(9999, ra.Max);
}
}
+
+ mi = typeof(MixAddress).GetProperty("Num");
+ mas = new List(rm.GetMemberAttributes(mi));
+ Assert.AreEqual(2, mas.Count);
+ foreach (var ma in mas)
+ {
+ if (ma is MinAttribute mia)
+ {
+ Assert.Contains(mia.Value, new[] { 100, 1000 });
+ }
+ }
+
}
[Test]
@@ -102,11 +116,11 @@ public void Members()
{
IClassMapping rm = new AttributeOverXmlClassMapping(GetXmlClassMapping(typeof (MixAddress)));
var mi = new List(rm.GetMembers());
- Assert.AreEqual(16, mi.Count); // the members of the class by reflection
+ Assert.AreEqual(18, mi.Count); // the members of the class by reflection
rm = new XmlOverAttributeClassMapping(GetXmlClassMapping(typeof (MixAddress)));
mi = new List(rm.GetMembers());
- Assert.AreEqual(16, mi.Count);
+ Assert.AreEqual(18, mi.Count);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Validator.Tests/Specifics/NHV119/Fixture.cs b/src/NHibernate.Validator.Tests/Specifics/NHV119/Fixture.cs
new file mode 100644
index 0000000..cc1c1a2
--- /dev/null
+++ b/src/NHibernate.Validator.Tests/Specifics/NHV119/Fixture.cs
@@ -0,0 +1,105 @@
+using System.Reflection;
+using NHibernate.Validator.Cfg;
+using NHibernate.Validator.Cfg.Loquacious;
+using NHibernate.Validator.Engine;
+using NUnit.Framework;
+using SharpTestsEx;
+
+namespace NHibernate.Validator.Tests.Specifics.NHV119
+{
+
+ [TestFixture]
+ public class Fixture : BaseValidatorFixture
+ {
+ [Test]
+ public void TestSameAttributeByDifferentTagsAttributeConfig()
+ {
+ //var vl = GetClassValidator(typeof(Model1));
+
+ var vtor = new ValidatorEngine();
+
+ var m = new Model1();
+
+ m.Qnt = 1000;
+ vtor.Validate(m).Should().Be.Empty();
+
+ m.Qnt = 50;
+ vtor.Validate(m).Should().Not.Be.Empty();
+
+ m.Qnt = 100;
+ vtor.Validate(m, "T2").Should().Be.Empty();
+
+ vtor.Validate(m, "T2", null).Should().Not.Be.Empty();
+
+ m.Qnt = 10;
+ vtor.Validate(m, "T1").Should().Be.Empty();
+ }
+
+ [Test]
+ public void TestSameAttributeByDifferentTagsXmlOverAttributeConfig()
+ {
+ //var vl = GetClassValidator(typeof(Model1));
+
+ var vtor = new ValidatorEngine();
+ var cfg = new XmlConfiguration();
+ cfg.Properties[Environment.ValidatorMode] = "OverrideAttributeWithExternal";
+ string an = Assembly.GetExecutingAssembly().FullName;
+ cfg.Mappings.Add(new MappingConfiguration(an, "NHibernate.Validator.Tests.Specifics.NHV119.Mappings.nhv.xml"));
+ vtor.Configure(cfg);
+
+ var m = new Model1();
+
+ m.Qnt = 1000;
+ vtor.Validate(m).Should().Be.Empty();
+
+ m.Qnt = 100;
+ vtor.Validate(m).Should().Not.Be.Empty();
+
+ m.Qnt = 20;
+ vtor.Validate(m, "T1").Should().Be.Empty();
+
+ m.Qnt = 19;
+ vtor.Validate(m, "T1").Should().Not.Be.Empty();
+
+
+ m.Qnt = 199;
+ vtor.Validate(m, "T2").Should().Not.Be.Empty();
+
+ m.Qnt = 200;
+ vtor.Validate(m, "T2").Should().Be.Empty();
+ }
+
+ [Test]
+ public void TestSameAttributeByDifferentTagsFluentConfig()
+ {
+ //var vl = GetClassValidator(typeof(Model1));
+
+
+ var configure = new FluentConfiguration();
+ configure.Register(new[] { typeof(Model1Validation) })
+ .SetDefaultValidatorMode(ValidatorMode.UseExternal);
+
+ var vtor = new ValidatorEngine();
+ vtor.Configure(configure);
+
+ var m = new Model1();
+
+ m.Qnt = 3000;
+ vtor.Validate(m).Should().Be.Empty();
+
+ m.Qnt = 300;
+ vtor.Validate(m).Should().Not.Be.Empty();
+
+ m.Qnt = 30;
+ vtor.Validate(m, "T1").Should().Be.Empty();
+
+
+ m.Qnt = 299;
+ vtor.Validate(m, "T2").Should().Not.Be.Empty();
+
+ m.Qnt = 3001;
+ vtor.Validate(m, "T2").Should().Be.Empty();
+ }
+ }
+
+}
diff --git a/src/NHibernate.Validator.Tests/Specifics/NHV119/Mappings.nhv.xml b/src/NHibernate.Validator.Tests/Specifics/NHV119/Mappings.nhv.xml
new file mode 100644
index 0000000..0b9d745
--- /dev/null
+++ b/src/NHibernate.Validator.Tests/Specifics/NHV119/Mappings.nhv.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/NHibernate.Validator.Tests/Specifics/NHV119/Model1.cs b/src/NHibernate.Validator.Tests/Specifics/NHV119/Model1.cs
new file mode 100644
index 0000000..fcd2507
--- /dev/null
+++ b/src/NHibernate.Validator.Tests/Specifics/NHV119/Model1.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using NHibernate.Validator.Constraints;
+
+namespace NHibernate.Validator.Tests.Specifics.NHV119
+{
+ public class Model1
+ {
+ [Min(10, Tags = "T1")]
+ [Min(777, Tags = "T2")] //This attribute will be ignored (redefined), by next one
+ [Min(100, Tags = "T2")] //And this will be redefined by xml config in TestSameAttributeByDifferentTagsXmlOverAttributeConfig test
+ [Min(1000)]
+ public int Qnt { get; set; }
+ }
+}
diff --git a/src/NHibernate.Validator.Tests/Specifics/NHV119/Model1Validation.cs b/src/NHibernate.Validator.Tests/Specifics/NHV119/Model1Validation.cs
new file mode 100644
index 0000000..5c99781
--- /dev/null
+++ b/src/NHibernate.Validator.Tests/Specifics/NHV119/Model1Validation.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using NHibernate.Validator.Cfg.Loquacious;
+
+namespace NHibernate.Validator.Tests.Specifics.NHV119
+{
+ public class Model1Validation : ValidationDef
+ {
+ public Model1Validation()
+ {
+ Define(x => x.Qnt).GreaterThanOrEqualTo(30).WithTags("T1");
+ Define(x => x.Qnt).GreaterThanOrEqualTo(300).WithTags("T2");
+ Define(x => x.Qnt).GreaterThanOrEqualTo(3000).WithTags("T2"); //This definition must override previous one
+ }
+ }
+}
diff --git a/src/NHibernate.Validator.Tests/Utils/AttributeUtilsFixture.cs b/src/NHibernate.Validator.Tests/Utils/AttributeUtilsFixture.cs
index 5d4c70d..55aba42 100644
--- a/src/NHibernate.Validator.Tests/Utils/AttributeUtilsFixture.cs
+++ b/src/NHibernate.Validator.Tests/Utils/AttributeUtilsFixture.cs
@@ -10,14 +10,14 @@ public class AttributeUtilsFixture
[Test]
public void AttributeCanBeMultiplied()
{
- PatternAttribute patternAttribute = new PatternAttribute();
+ var patternAttribute = new PatternAttribute();
Assert.AreEqual(true, (AttributeUtils.AttributeAllowsMultiple(patternAttribute)));
}
[Test]
public void AttributeCannotBeMultiplied()
{
- LengthAttribute lenghtAttribute = new LengthAttribute();
+ var lenghtAttribute = new IBANAttribute();
Assert.AreEqual(false, (AttributeUtils.AttributeAllowsMultiple(lenghtAttribute)));
}
}
diff --git a/src/NHibernate.Validator/Constraints/DecimalMaxAttribute.cs b/src/NHibernate.Validator/Constraints/DecimalMaxAttribute.cs
index 7598e6b..33221ae 100644
--- a/src/NHibernate.Validator/Constraints/DecimalMaxAttribute.cs
+++ b/src/NHibernate.Validator/Constraints/DecimalMaxAttribute.cs
@@ -3,6 +3,7 @@
using System.Globalization;
using NHibernate.Mapping;
using NHibernate.Validator.Engine;
+using NHibernate.Validator.Util;
namespace NHibernate.Validator.Constraints
{
@@ -10,7 +11,7 @@ namespace NHibernate.Validator.Constraints
/// Max restriction on a numeric annotated element
///
[Serializable]
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public class DecimalMaxAttribute : EmbeddedRuleArgsAttribute, IRuleArgs, IValidator, IPropertyConstraint
{
private string message = "{validator.max}";
@@ -98,6 +99,9 @@ public bool IsValid(object value, IConstraintValidatorContext validatorContext)
public void Apply(Property property)
{
+ if (AttributeUtils.AttributeUsedMultipleTimesOnProperty(property, GetType()))
+ return;
+
IEnumerator ie = property.ColumnIterator.GetEnumerator();
ie.MoveNext();
var col = (Column)ie.Current;
diff --git a/src/NHibernate.Validator/Constraints/DecimalMinAttribute.cs b/src/NHibernate.Validator/Constraints/DecimalMinAttribute.cs
index fae2039..5d69032 100644
--- a/src/NHibernate.Validator/Constraints/DecimalMinAttribute.cs
+++ b/src/NHibernate.Validator/Constraints/DecimalMinAttribute.cs
@@ -3,6 +3,7 @@
using System.Globalization;
using NHibernate.Mapping;
using NHibernate.Validator.Engine;
+using NHibernate.Validator.Util;
namespace NHibernate.Validator.Constraints
{
@@ -10,7 +11,7 @@ namespace NHibernate.Validator.Constraints
/// Min restriction on a numeric annotated element (or the string representation of a numeric)
///
[Serializable]
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public class DecimalMinAttribute : EmbeddedRuleArgsAttribute, IRuleArgs, IValidator, IPropertyConstraint
{
private string message = "{validator.min}";
@@ -95,6 +96,9 @@ public bool IsValid(object value, IConstraintValidatorContext validatorContext)
public void Apply(Property property)
{
+ if (AttributeUtils.AttributeUsedMultipleTimesOnProperty(property, GetType()))
+ return;
+
IEnumerator ie = property.ColumnIterator.GetEnumerator();
ie.MoveNext();
var col = (Column)ie.Current;
diff --git a/src/NHibernate.Validator/Constraints/DelegatedValidatorAttribute.cs b/src/NHibernate.Validator/Constraints/DelegatedValidatorAttribute.cs
index 8b81acb..3e6a199 100644
--- a/src/NHibernate.Validator/Constraints/DelegatedValidatorAttribute.cs
+++ b/src/NHibernate.Validator/Constraints/DelegatedValidatorAttribute.cs
@@ -1,10 +1,12 @@
using System;
using NHibernate.Validator.Engine;
+using NHibernate.Validator.Util;
namespace NHibernate.Validator.Constraints
{
[Serializable]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
+ [AllowsMultipleWithIntersectingTags]
[CLSCompliant(false)]
public class DelegatedValidatorAttribute : EmbeddedRuleArgsAttribute, IValidatorInstanceProvider, IRuleArgs
{
@@ -23,4 +25,4 @@ public IValidator Validator
get { return validatorInstance; }
}
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Validator/Constraints/LengthAttribute.cs b/src/NHibernate.Validator/Constraints/LengthAttribute.cs
index f4e138e..c36a952 100644
--- a/src/NHibernate.Validator/Constraints/LengthAttribute.cs
+++ b/src/NHibernate.Validator/Constraints/LengthAttribute.cs
@@ -1,7 +1,9 @@
using System;
using System.Collections;
+using System.Reflection;
using NHibernate.Mapping;
using NHibernate.Validator.Engine;
+using NHibernate.Validator.Util;
namespace NHibernate.Validator.Constraints
{
@@ -9,7 +11,7 @@ namespace NHibernate.Validator.Constraints
/// Apply some length restrictions to the annotated element. It has to be a string
///
[Serializable]
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public class LengthAttribute : EmbeddedRuleArgsAttribute, IRuleArgs, IValidator, IPropertyConstraint
{
private string message = "{validator.length}";
@@ -67,6 +69,9 @@ public bool IsValid(object value, IConstraintValidatorContext validatorContext)
public void Apply(Property property)
{
+ if (AttributeUtils.AttributeUsedMultipleTimesOnProperty(property, GetType()))
+ return;
+
IEnumerator ie = property.ColumnIterator.GetEnumerator();
ie.MoveNext();
var col = (Column)ie.Current;
@@ -79,4 +84,4 @@ public void Apply(Property property)
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Validator/Constraints/MaxAttribute.cs b/src/NHibernate.Validator/Constraints/MaxAttribute.cs
index ffdbd4c..678b65c 100644
--- a/src/NHibernate.Validator/Constraints/MaxAttribute.cs
+++ b/src/NHibernate.Validator/Constraints/MaxAttribute.cs
@@ -2,6 +2,7 @@
using System.Collections;
using NHibernate.Mapping;
using NHibernate.Validator.Engine;
+using NHibernate.Validator.Util;
namespace NHibernate.Validator.Constraints
{
@@ -9,7 +10,7 @@ namespace NHibernate.Validator.Constraints
/// Max restriction on a numeric annotated element
///
[Serializable]
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public class MaxAttribute : EmbeddedRuleArgsAttribute, IRuleArgs, IValidator, IPropertyConstraint
{
private string message = "{validator.max}";
@@ -70,6 +71,9 @@ public bool IsValid(object value, IConstraintValidatorContext validatorContext)
public void Apply(Property property)
{
+ if (AttributeUtils.AttributeUsedMultipleTimesOnProperty(property, GetType()))
+ return;
+
IEnumerator ie = property.ColumnIterator.GetEnumerator();
ie.MoveNext();
var col = (Column)ie.Current;
@@ -78,4 +82,4 @@ public void Apply(Property property)
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Validator/Constraints/MinAttribute.cs b/src/NHibernate.Validator/Constraints/MinAttribute.cs
index 185f4db..debae4c 100644
--- a/src/NHibernate.Validator/Constraints/MinAttribute.cs
+++ b/src/NHibernate.Validator/Constraints/MinAttribute.cs
@@ -2,6 +2,7 @@
using System.Collections;
using NHibernate.Mapping;
using NHibernate.Validator.Engine;
+using NHibernate.Validator.Util;
namespace NHibernate.Validator.Constraints
{
@@ -9,7 +10,7 @@ namespace NHibernate.Validator.Constraints
/// Min restriction on a numeric annotated element (or the string representation of a numeric)
///
[Serializable]
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public class MinAttribute : EmbeddedRuleArgsAttribute, IRuleArgs, IValidator, IPropertyConstraint
{
private string message = "{validator.min}";
@@ -64,10 +65,13 @@ public bool IsValid(object value, IConstraintValidatorContext validatorContext)
public void Apply(Property property)
{
+ if (AttributeUtils.AttributeUsedMultipleTimesOnProperty(property, GetType()))
+ return;
+
IEnumerator ie = property.ColumnIterator.GetEnumerator();
ie.MoveNext();
var col = (Column)ie.Current;
col.CheckConstraint = col.Name + ">=" + Value;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Validator/Constraints/PatternAttribute.cs b/src/NHibernate.Validator/Constraints/PatternAttribute.cs
index 021bce7..b39ce92 100644
--- a/src/NHibernate.Validator/Constraints/PatternAttribute.cs
+++ b/src/NHibernate.Validator/Constraints/PatternAttribute.cs
@@ -1,6 +1,7 @@
using System;
using System.Text.RegularExpressions;
using NHibernate.Validator.Engine;
+using NHibernate.Validator.Util;
namespace NHibernate.Validator.Constraints
{
@@ -9,6 +10,7 @@ namespace NHibernate.Validator.Constraints
///
[Serializable]
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
+ [AllowsMultipleWithIntersectingTags]
public class PatternAttribute : EmbeddedRuleArgsAttribute, IRuleArgs, IValidator
{
private RegexOptions flags = RegexOptions.Compiled;
@@ -66,4 +68,4 @@ protected Regex GetRegex()
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Validator/Constraints/RangeAttribute.cs b/src/NHibernate.Validator/Constraints/RangeAttribute.cs
index 9e28605..82187fb 100644
--- a/src/NHibernate.Validator/Constraints/RangeAttribute.cs
+++ b/src/NHibernate.Validator/Constraints/RangeAttribute.cs
@@ -2,6 +2,7 @@
using System.Collections;
using NHibernate.Mapping;
using NHibernate.Validator.Engine;
+using NHibernate.Validator.Util;
namespace NHibernate.Validator.Constraints
{
@@ -10,7 +11,7 @@ namespace NHibernate.Validator.Constraints
/// representation of the numeric value.
///
[Serializable]
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public class RangeAttribute : EmbeddedRuleArgsAttribute, IRuleArgs, IValidator, IPropertyConstraint
{
private long max = long.MaxValue;
@@ -94,6 +95,10 @@ public bool IsValid(object value, IConstraintValidatorContext validatorContext)
public void Apply(Property property)
{
+ if (AttributeUtils.AttributeUsedMultipleTimesOnProperty(property, GetType()))
+ return;
+
+
IEnumerator ie = property.ColumnIterator.GetEnumerator();
ie.MoveNext();
var col = (Column)ie.Current;
@@ -116,4 +121,4 @@ public void Apply(Property property)
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Validator/Constraints/SizeAttribute.cs b/src/NHibernate.Validator/Constraints/SizeAttribute.cs
index 8822830..2249ce7 100644
--- a/src/NHibernate.Validator/Constraints/SizeAttribute.cs
+++ b/src/NHibernate.Validator/Constraints/SizeAttribute.cs
@@ -18,7 +18,7 @@ namespace NHibernate.Validator.Constraints
///
///
[Serializable]
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public class SizeAttribute : EmbeddedRuleArgsAttribute, IRuleArgs, IValidator
{
private int max = int.MaxValue;
@@ -92,4 +92,4 @@ public bool IsValid(object value, IConstraintValidatorContext validatorContext)
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Validator/Constraints/WithinAttribute.cs b/src/NHibernate.Validator/Constraints/WithinAttribute.cs
index f4bc3bf..3f5a56c 100644
--- a/src/NHibernate.Validator/Constraints/WithinAttribute.cs
+++ b/src/NHibernate.Validator/Constraints/WithinAttribute.cs
@@ -3,15 +3,16 @@
using System.Text;
using NHibernate.Mapping;
using NHibernate.Validator.Engine;
+using NHibernate.Validator.Util;
namespace NHibernate.Validator.Constraints
{
///
- /// The annotated elemnt has to be in the appropriate range (excluding both limits).
+ /// The annotated element has to be in the appropriate range (excluding both limits).
/// Apply on numeric values can be converted to double ().
///
[Serializable]
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public class WithinAttribute : EmbeddedRuleArgsAttribute, IRuleArgs, IValidator, IPropertyConstraint
{
private string message = "{validator.within}";
@@ -88,6 +89,9 @@ public bool IsValid(object value, IConstraintValidatorContext constraintValidato
public void Apply(Property property)
{
+ if (AttributeUtils.AttributeUsedMultipleTimesOnProperty(property, GetType()))
+ return;
+
var col = property.ColumnIterator.OfType().First();
var check = new StringBuilder(80);
@@ -108,4 +112,4 @@ public void Apply(Property property)
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Validator/Engine/ClassValidator.cs b/src/NHibernate.Validator/Engine/ClassValidator.cs
index df90c7b..404cffe 100644
--- a/src/NHibernate.Validator/Engine/ClassValidator.cs
+++ b/src/NHibernate.Validator/Engine/ClassValidator.cs
@@ -207,6 +207,9 @@ private void InitValidator(System.Type clazz, IDictionary();
+
foreach (MemberInfo member in map.GetMembers())
{
var memberAttributes = map.GetMemberAttributes(member);
@@ -221,7 +224,10 @@ private void InitValidator(System.Type clazz, IDictionary 0)
+ {
+ membersToValidate.AddRange(membersToValidateFor1Memeber);
+ membersToValidateFor1Memeber.Clear();
+ }
}
}
+ private void RemoveSameTypeValidatorWithIntersectingTags(List membersToValidateFor1Memeber, ITagableRule newAttr)
+ {
+ membersToValidateFor1Memeber.RemoveAll(x => x.ValidatorDef.Validator.GetType() == newAttr.GetType()
+ && ((x.ValidatorDef.Tags == null && newAttr.TagCollection == null)
+ || x.ValidatorDef.Tags.Intersect(newAttr.TagCollection).Any()
+ ));
+ }
+
private void AddAttributeToMember(MemberInfo currentMember, Attribute thisattribute)
{
#if NETFX
diff --git a/src/NHibernate.Validator/Mappings/MixedClassMapping.cs b/src/NHibernate.Validator/Mappings/MixedClassMapping.cs
index 5196614..a5f62a1 100644
--- a/src/NHibernate.Validator/Mappings/MixedClassMapping.cs
+++ b/src/NHibernate.Validator/Mappings/MixedClassMapping.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Reflection;
+using NHibernate.Validator.Engine;
using NHibernate.Validator.Util;
namespace NHibernate.Validator.Mappings
@@ -22,37 +24,59 @@ protected virtual void InitializeClassAttributes(IClassMapping baseMap, IClassMa
protected void MixMembersWith(HashSet lmembers, IClassMapping mapping)
{
- foreach (MemberInfo info in mapping.GetMembers())
+ foreach (var info in mapping.GetMembers())
{
lmembers.Add(info);
- IEnumerable mas = mapping.GetMemberAttributes(info);
- if (mas != null)
+ var mas = mapping.GetMemberAttributes(info);
+ if (mas == null)
+ continue;
+
+ if (!membersAttributesDictionary.TryGetValue(info, out var attrs))
{
- List attrs;
- if (!membersAttributesDictionary.TryGetValue(info, out attrs))
- {
- membersAttributesDictionary[info] = new List(mas);
- }
- else
- {
- CombineAttribute(mas, attrs);
- membersAttributesDictionary[info] = attrs;
- }
+ membersAttributesDictionary[info] = new List(mas);
+ }
+ else
+ {
+ CombineAttribute(mas, attrs);
+ membersAttributesDictionary[info] = attrs;
}
}
}
protected static void CombineAttribute(IEnumerable origin, List dest)
{
- foreach (Attribute ma in origin)
+ foreach (var ma in origin)
{
- Attribute found = dest.Find(attribute => ma.TypeId.Equals(attribute.TypeId));
+ var founded = dest.FindAll(attribute => ma.TypeId.Equals(attribute.TypeId));
- if (found != null && !AttributeUtils.AttributeAllowsMultiple(ma))
- dest.Remove(found);
+ if (founded.Count > 0)
+ {
+ if (!AttributeUtils.AttributeAllowsMultiple(ma))
+ {
+ dest.Remove(founded[0]);
+ }
+ else
+ {
+ if ((ma is ITagableRule matr) && !AttributeUtils.AttributeAllowsMultipleWithIntersectingTags(ma))
+ {
+ foreach (var fd in founded)
+ {
+ if (!(fd is ITagableRule fdtr))
+ continue;
+
+ if ((fdtr.TagCollection.Count == 0 && matr.TagCollection.Count == 0)
+ || fdtr.TagCollection.Intersect(matr.TagCollection).Any()
+ )
+ {
+ dest.Remove(fd);
+ }
+ }
+ }
+ }
+ }
dest.Add(ma);
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/NHibernate.Validator/Mappings/OpenClassMapping.cs b/src/NHibernate.Validator/Mappings/OpenClassMapping.cs
index 1411d62..f3271c2 100644
--- a/src/NHibernate.Validator/Mappings/OpenClassMapping.cs
+++ b/src/NHibernate.Validator/Mappings/OpenClassMapping.cs
@@ -55,7 +55,7 @@ public void AddEntityValidator(Attribute attribute)
{
if (attribute == null)
{
- throw new ArgumentNullException("attribute");
+ throw new ArgumentNullException(nameof(attribute));
}
// TODO : check attribute in order to validate that it is a valid Entity-Validator attribute
classAttributes.Add(attribute);
@@ -65,11 +65,11 @@ public void AddConstraint(PropertyInfo property, Attribute attribute)
{
if (property == null)
{
- throw new ArgumentNullException("property");
+ throw new ArgumentNullException(nameof(property));
}
if (attribute == null)
{
- throw new ArgumentNullException("attribute");
+ throw new ArgumentNullException(nameof(attribute));
}
AddMemberConstraint(property, attribute);
}
@@ -78,41 +78,41 @@ public void AddConstraint(FieldInfo field, Attribute attribute)
{
if (field == null)
{
- throw new ArgumentNullException("field");
+ throw new ArgumentNullException(nameof(field));
}
if (attribute == null)
{
- throw new ArgumentNullException("attribute");
+ throw new ArgumentNullException(nameof(attribute));
}
AddMemberConstraint(field, attribute);
}
public void AddMemberConstraint(MemberInfo member, Attribute attribute)
{
- List constraints;
-
- if (!membersAttributesDictionary.TryGetValue(member, out constraints))
+ if (!membersAttributesDictionary.TryGetValue(member, out var constraints))
{
constraints = new List();
membersAttributesDictionary.Add(member, constraints);
}
- Attribute found = constraints.Find(x => x.TypeId.Equals(attribute.TypeId));
+ var found = constraints.Find(x => x.TypeId.Equals(attribute.TypeId));
if (found == null || AttributeUtils.AttributeAllowsMultiple(attribute))
{
+ constraints.Add(attribute);
+ //Not possible to stop adding constraints here based on intersecting tags, because Tags not yet assigned when this code is executed
+
#if NETFX
log.Debug(string.Format("For class {0} Adding member {1} to dictionary with attribute {2}", EntityType.FullName,
- member.Name, attribute));
+ member.Name, attribute));
#else
Log.Debug("For class {0} Adding member {1} to dictionary with attribute {2}", EntityType.FullName,
member.Name, attribute);
#endif
- membersAttributesDictionary[member].Add(attribute);
}
else
{
#if NETFX
- log.Debug("Duplicated Attribute avoided: Class:" + typeof(T).FullName + " Member:" + member.Name + " Attribute:"
- + attribute);
+ log.Debug("Duplicated Attribute avoided: Class:" + typeof(T).FullName + " Member:" + member.Name + " Attribute:" +
+ attribute);
#else
Log.Debug("Duplicated Attribute avoided: Class: {0} Member: {1} Attribute: {2}", typeof(T).FullName,
member.Name, attribute);
diff --git a/src/NHibernate.Validator/Util/AllowsMultipleWithIntersectingTagsAttribute.cs b/src/NHibernate.Validator/Util/AllowsMultipleWithIntersectingTagsAttribute.cs
new file mode 100644
index 0000000..2effb87
--- /dev/null
+++ b/src/NHibernate.Validator/Util/AllowsMultipleWithIntersectingTagsAttribute.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace NHibernate.Validator.Util
+{
+ ///
+ /// Specify if constraint attribute can be used multiple times with intersecting tags. (No tags, or same tags)
+ ///
+ [AttributeUsage(AttributeTargets.Class)]
+ public class AllowsMultipleWithIntersectingTagsAttribute : Attribute
+ {
+ }
+}
diff --git a/src/NHibernate.Validator/Util/AttributeUtils.cs b/src/NHibernate.Validator/Util/AttributeUtils.cs
index 887fb52..aedf6f1 100644
--- a/src/NHibernate.Validator/Util/AttributeUtils.cs
+++ b/src/NHibernate.Validator/Util/AttributeUtils.cs
@@ -1,4 +1,6 @@
using System;
+using System.Reflection;
+using NHibernate.Mapping;
namespace NHibernate.Validator.Util
{
@@ -14,8 +16,46 @@ public static class AttributeUtils
///
public static bool AttributeAllowsMultiple(Attribute attribute)
{
- Attribute usageAttribute = Attribute.GetCustomAttribute(attribute.GetType(), typeof(AttributeUsageAttribute));
+ var usageAttribute = Attribute.GetCustomAttribute(attribute.GetType(), typeof(AttributeUsageAttribute));
return ((AttributeUsageAttribute)usageAttribute).AllowMultiple;
}
+
+ ///
+ /// Returns true if the attribute can be declared more than one time for the same element and this attribute marked with [AllowsMultipleWithSameTags]
+ ///
+ ///
+ ///
+ public static bool AttributeAllowsMultipleWithIntersectingTags(Attribute attribute)
+ {
+ var attr = Attribute.GetCustomAttribute(attribute.GetType(), typeof(AllowsMultipleWithIntersectingTagsAttribute));
+ return AttributeAllowsMultiple(attribute) && attr != null;
+ }
+
+ ///
+ /// Return true if same attribute applied to property or field more then 1 time. It can happens when attribute used with different tags
+ ///
+ ///
+ ///
+ ///
+ public static bool AttributeUsedMultipleTimesOnProperty(Property property, System.Type attributeType)
+ {
+ //Next happens for component properties. Not possible to access component class metadata back from Property in NHib 5.0
+ //TODO: How to fix this?
+ if (property.PersistentClass == null)
+ return false;
+
+ var tp = System.Type.GetType(property.PersistentClass.ClassName);
+ var member = (MemberInfo) tp.GetProperty(property.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+
+ if (member == null)
+ member = tp.GetField(property.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+
+ if (member == null)
+ return false;
+
+ var attributes = member.GetCustomAttributes(attributeType, true);
+ return attributes.Length > 1;
+
+ }
}
}