-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NHV-119 - Handle multiple attributes #17
base: master
Are you sure you want to change the base?
Conversation
For many attributes AllowMultiple=true; If several attributes with different tags defined on property no Nhib mappings changes; If several attribute with same tag defined for property as attribute or using fluent configuration - last defined attribute override all previous with same tag;
I have reworded your description for having plain sentences, but for "no NHib mappings changes", I am not making sens of it. The first part of the sentence looks to me as the thing that is asked by NHV-119, so "no changes" looks a bit contradictory. What is a change that would change nothing? Please also prioritize the most meaningful information in the commit: the first line should directly tell what the change is about. "Fix & tests" is quite unhelpful, we are left to lookup the ticket. "Handle multiple attributes" (what I have edited in the PR description and title) tells more about the subject. You can put the "Fix & tests" at the very end of the commit message just to let know if you wish, but this information could also be dropped. That looks to me as the default for a PR/commit. |
Assert.AreEqual(true, (AttributeUtils.AttributeAllowsMultiple(patternAttribute))); | ||
} | ||
|
||
[Test] | ||
public void AttributeCannotBeMultiplied() | ||
{ | ||
LengthAttribute lenghtAttribute = new LengthAttribute(); | ||
var lenghtAttribute = new IBANAttribute(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable name should be changed too.
if (AttributeUtils.AttributeUsedMultipleTimesOnProperty(property, GetType())) | ||
return; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double blank line.
@@ -207,6 +207,9 @@ private void InitValidator(System.Type clazz, IDictionary<System.Type, IClassVal | |||
ValidateClassAtribute(classAttribute); | |||
} | |||
|
|||
|
|||
var membersToValidateFor1Memeber = new List<Member>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in variable name. And well, in fact those Member
are more validator definition than members. A more meaningful name for that variable could then be memberValidators
.
membersToValidateFor1Memeber.RemoveAll(x => x.ValidatorDef.Validator.GetType() == newAttr.GetType() | ||
&& ((x.ValidatorDef.Tags == null && newAttr.TagCollection == null) | ||
|| x.ValidatorDef.Tags.Intersect(newAttr.TagCollection).Any() | ||
)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This need renaming, rewriting and reformatting, for maintainability and correctness. Please use semantic naming (what is it meant to do, rather than what it technically does).
By example:
private void RemoveOverridenValidators(System.Type clazz, List<Member> memberValidators, ITagableRule newValidator)
{
var newValidatorType = newValidator.GetType();
var newValidatorIsUntagged = newValidator.TagCollection.Count == 0;
var removedCount = memberValidators
.RemoveAll(
v => v.ValidatorDef.Validator.GetType() == newValidatorType && (
(v.ValidatorDef.Tags == null || v.ValidatorDef.Tags.Count == 0) && newValidatorIsUntagged ||
v.ValidatorDef.Tags != null && !newValidatorIsUntagged && v.ValidatorDef.Tags.Intersect(newValidator.TagCollection).Any()));
if (removedCount > 0)
{
#if NETFX
log.Debug(
"Validators of the same type having some tags in common (or both without tags) found on a " +
"member, keeping only the last defined: class " + clazz.FullName + ", member " + v.Getter.Name +
", last validator " + newValidator);
#else
Log.Debug(
"Validators of the same type having some tags in common (or both without tags) found on a " +
"member, keeping only the last defined: class {0}, member: {1}, last validator {2}",
clazz.FullName, v.Getter.Name, newValidator);
#endif
}
}
I have removed the null check on TagCollection
since it is never checked everywhere else and that current implementations never yields null. I also have added a log for helping diagnosing rule overrides.
But shouldn't it check AllowsMultipleWithIntersectingTags
before removing?
if (AttributeUtils.AttributeUsedMultipleTimesOnProperty(property, GetType())) | ||
return; | ||
|
||
|
||
IEnumerator ie = property.ColumnIterator.GetEnumerator(); | ||
ie.MoveNext(); | ||
var col = (Column)ie.Current; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GetEnumerator
yields an IEnumerator<ISelectable> which is disposable, and not disposed of... This kind of old code should be modernized when met, for using extension methods like
First` instead.
namespace NHibernate.Validator.Util | ||
{ | ||
/// <summary> | ||
/// Specify if constraint attribute can be used multiple times with intersecting tags. (No tags, or same tags) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parenthesis is misleading I think. It should be `(No tags, or some tags in common.)
public static bool AttributeAllowsMultipleWithIntersectingTags(Attribute attribute) | ||
{ | ||
var attr = Attribute.GetCustomAttribute(attribute.GetType(), typeof(AllowsMultipleWithIntersectingTagsAttribute)); | ||
return AttributeAllowsMultiple(attribute) && attr != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert condition order: when using short-circuiting boolean operators, the less costly operation should be done first.
} | ||
|
||
/// <summary> | ||
/// Return true if same attribute applied to property or field more then 1 time. It can happens when attribute used with different tags |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Many typo and syntax troubles.
Return true if the same attribute is applied to the property or field more than one time. It can happen when the attribute is 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? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment on Apply
.
@@ -98,6 +99,9 @@ public bool IsValid(object value, IConstraintValidatorContext validatorContext) | |||
|
|||
public void Apply(Property property) | |||
{ | |||
if (AttributeUtils.AttributeUsedMultipleTimesOnProperty(property, GetType())) | |||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be done for all IPropertyConstraint
with AllowMultiple
. Then better move that check into ClassValidator
, for not calling this method at all when constraints should not be generated (when the attribute allows multiple and is defined multiple times). By the way, this should allow to fix the component case, since ClassValidator
has access to more data about the property.
Now after reviewing I can understand a bit more "If several attributes with different tags defined on property no Nhib mappings changes", but it appears to be wrong. Tags are not checked anywhere for disabling the constraint "enrichment" that some attributes may do. I am changing that to: If several attributes of the same type are defined on a property, their constraint injection in NHibernate mapping is disabled. |
Hello |
Yes then, invert it. |
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify what happens in that case? Is the fluent configuration checked and "cleaned up" later anyway? Or does this cause the overriding to not occur in this case, letting all attributes applied even if contradictory?
NHV-119 - Handle multiple attributes, fix & tests.
For many attributes, enable
AllowMultiple
.If several attributes of the same type are defined on a property, their constraint injection in NHibernate mapping is disabled.
If several attributes of the same type are defined (as attribute or using fluent configuration) with overlapping tags (or without tags at all) on a property, the last defined attribute override all previous ones.