Add option to ScalePrecisionValidator to check digits to left of decimal point
See original GitHub issueSystem Details
- FluentValidation version: 8.1.2
- Web Framework version: ASP.NET Core 2.1
Issue Description
When using ScalePrecisionValidator to validate input that is going to be saved into MS SQL Server, the validation can pass, but then fail to save into SQL Server due to a difference in how SQL Server looks at precision and scale and how FluentValidation is using it.
If you look at the Decimal Type documentation for SQL Server. It says:
s (scale) The number of decimal digits that will be stored to the right of the decimal point. This number is subtracted from p to determine the maximum number of digits to the left of the decimal point.
If you look at the code for ScalePrecisionValidator. It is just checking if (scale > Scale || precision > Precision)
. It doesn’t care about how many digits are to the left of the decimal point.
It would be nice to add an option so the behavior of ScalePrecisionValidator could be set up to match what SQL Server expects. This could be something like how IgnoreTrailingZeros works so you opt-in to using this different behavior. I can put up a PR for this change, but wanted to double check if it would be a good approach to this since I saw in #151 that it was just recommended to use a custom validator for this. I think it would be useful for this to be built into ScalePrecisionValidator since SQL Server is a commonly used database and its not obvious what is going wrong when you first run into this difference between the two.
Here is an example of a validator that passes, but then fails when the input goes down to SQL Server.
using FluentValidation;
public class TestClass
{
public decimal Value { get; set; }
}
public class TestValidator : AbstractValidator<TestClass>
{
public TestValidator()
{
RuleFor(x => x.Value).SetValidator(new ScalePrecisionValidator(4, 9) {IgnoreTrailingZeros = true});
}
}
var testClass = new TestClass{Value = 123456};
var validator = new TestValidator();
// This passes
var result = validator.Validate(testClass);
However if the SQL Server Value
column is also set to a scale of 4 and a precision of 9, inserting the value 123456
throws System.Data.SqlClient.SqlException (0x80131904): Error converting data type numeric to decimal.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:1
- Comments:17 (13 by maintainers)
Top GitHub Comments
Ok, sounds good. If you’d like to get this updated then that’d be appreciated and I’ll happily give it a review.
I didn’t write it - it was a contribution to the project made in 2012. I assume it was based on this stackoverflow answer from 2009, as the code is very similar, but I don’t know for sure 🤷♂️
My understanding was the original intent of the validator was just to validate the scale value and the precision value - validating the number of digits clearly wasn’t the original author’s intent.
As I posted above, I am very open to this being changed if it would make it more useful but the implications of a breaking change have to be considered (both in terms of functionality, and also re-translation of error messsages), which is why I think @KevinHicksSW’s idea of a subclass is better for now. This is currently waiting on @KevinHicksSW (or someone else) to provide an updated PR, at which point I can get it reviewed and merged.
I’m also open to making this the default behaviour in future, but as that’s a breaking change it’d need to be for a major release (9.0 is the next, which I haven’t started working on yet).