【问题标题】:Best Data annotation for a Decimal(18,2)十进制的最佳数据注释(18,2)
【发布时间】:2013-11-17 15:17:06
【问题描述】:

我的 sql server 2008 中有一个列,类型为 Decimal(18,2)。但是在实体框架上,我可以在我的 asp.net MVC Web 应用程序中应用到这个属性的最佳数据注释验证是什么?

【问题讨论】:

  • 你的意思是,将其限制为 2 位小数?
  • 是的,这样数据库就不会出现异常了!!
  • @jumpingcode 在下面的回答正确,你应该接受。

标签: c# asp.net-mvc entity-framework


【解决方案1】:

小数点没有明确的数据注释,因此您需要使用两个单独的注释来添加约束。

两个小数点

[RegularExpression(@"^\d+(\.\d{1,2})?$")]

这个正则表达式将确保属性最多有两位小数。

最多 18 位数字

[Range(0, 9999999999999999.99)]

假设您不接受任何负数。否则,将0 替换为-9999999999999999.99

结果

[RegularExpression(@"^\d+(\.\d{1,2})?$")]
[Range(0, 9999999999999999.99)]
public decimal Property { get; set; }

【讨论】:

  • 这个正则表达式无效尝试输入1234m12,它将通过表达式。点需要被转义,因为它被视为任何字符。 [正则表达式(@"^\d+\.\d{0,2}$")]
  • 我相信您示例中的正则表达式应该是“^\d*.\d{0,2}$”。否则单个数字值将是不可接受的,但 OP 应该可以接受单个数字值。
  • @Jay 如何获得像 (0.1234) 或 (456.0009) 这样的小数?
  • 很好的答案,但是,我发现正则表达式迫使你必须有小数位,这对于我的用例来说不是我需要的,所以使小数位可选的正则表达式是:“^ \d+(\.\d{1,2})?$" 这对于输入货币等非常有用。
  • 重要的是要注意 RegularExpressionAttribute 在将要测试的值转换为字符串时会考虑当前区域性(以便根据提供的正则表达式对其进行测试),因此如果当前区域性的小数点是逗号(可能是),那么您需要在正则表达式中考虑到它。
【解决方案2】:

我认为@jumpingcode 的答案可以合并为一个RegularExpressionAttribute

[RegularExpression(@"^(0|-?\d{0,16}(\.\d{0,2})?)$")]
public decimal Property
{
    get;
    set;
}

这可用于任何precisionscale。 16 替换为precision - scale,2 替换为scale。正则表达式应匹配输入的数字,如 ###0.##.##0###.## 以及负值。

【讨论】:

  • 如果要经常使用,扩展 RegularExpression 属性可能是最好的选择。然后你可以有一个属性来提供精度和比例。
【解决方案3】:

对于某些人可能认为更具可读性的不同方法,您可以覆盖 DbContext 的 OnModelCreating 方法来设置精度,如下所示:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

           modelBuilder.Entity<YourEntity>()
                    .Property(x => x.TheProprty)
                    .HasPrecision(18, 2);
    }

优势:强类型 vs 自定义正则表达式

缺点:仅扫描无法在课堂上看到它

【讨论】:

    【解决方案4】:

    如果您编写“列”注释,则可以正常工作

        [Required]
        [Column(TypeName = "decimal(18, 6)")]
        public decimal Foo { get; set; }
    

    【讨论】:

    • 它不适用于 ASPNET MVC。我在运行迁移时收到此消息The store type 'decimal(18, 8)' could not be found in the SqlServer provider manifest
    • 这种方法对我来说也是同样的结果。
    【解决方案5】:

    这似乎是正确的答案(以上答案要么限制可以插入到 Decimal(18,2) 数据类型中的有效数字,要么在将它们应用于代码时导致编译错误——请自行确认):

    同时使用以下两个约束:

    两个小数点

    [RegularExpression(@"^\d+.?\d{0,2}$", ErrorMessage = "Invalid Target Price; Maximum Two Decimal Points.")]
    

    最多 18 位数字

      [Range(0, 9999999999999999.99, ErrorMessage = "Invalid Target Price; Max 18 digits")]
    

    【讨论】:

      【解决方案6】:

      继@Schmalls 示例之后(并评论将其重新构建为属性),我创建了一个工作示例(使用 C# 6 字符串插值):

      public class PrecisionAndScaleAttribute : RegularExpressionAttribute
      {
          public PrecisionAndScaleAttribute(int precision, int scale) : base($@"^(0|-?\d{{0,{precision - scale}}}(\.\d{{0,{scale}}})?)$")
          {
      
          }
      }
      

      用法:

      [PrecisionAndScale(6, 2, ErrorMessage = "Total Cost must not exceed $9999.99")]
      public decimal TotalCost { get; set; }
      

      【讨论】:

      【解决方案7】:

      EF Core 6

      你可以简单地使用:

      [Precision(18,2)]
      public decimal Property{ get; set; }
      

      【讨论】:

        【解决方案8】:
         [Range(1,(double) decimal.MaxValue, ErrorMessage="value should be between{1} and {2}."]
        

        【讨论】:

          【解决方案9】:

          我使用的几乎是 excplusively(b/c 它简单且有效)

          [Range(typeof(decimal), "0", "1")]
          public decimal Split { get; set; }
          

          如果我需要转换回双精度,我会添加一个转换

          (double)model.Split
          

          【讨论】:

            【解决方案10】:

            .net core/5/6 解决方案,适用于 2021 年

            using System;
            using System.ComponentModel.DataAnnotations;
            using System.Text.RegularExpressions;
            
            [AttributeUsage(AttributeTargets.Property)]
            public class ScalePrecisionValidationAttribute : ValidationAttribute
            {
                private int _scale;
                private int _precision;
            
                public ScalePrecisionValidationAttribute(int scale, int precision)
                {
                    _scale = scale;
                    _precision = precision;
                }
            
                protected override ValidationResult IsValid(object value, ValidationContext validationContext)
                {
                    if (value != null)
                    {
                        if (!Regex.IsMatch(value.ToString(), $@"^(0|-?\d{{0,{scale-precision}}}(\.\d{{0,{precision}}})?)$"))
                        {
                            return new ValidationResult($"Allowed scale: {_scale}, precision: {_precision}");
                        }
                    }
            
                    return ValidationResult.Success;
                }
            }
            

            用作

            [ScalePrecisionValidationAttribute(8, 3)]
            public decimal Weight { get; set; }
            

            您可能希望根据用例添加/修改额外的防护。 p.s.我使用了其他答案之一中的Regex 模式

            【讨论】:

            • @GertArnold 谢谢。已编辑
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-01-26
            • 2013-07-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-09-24
            • 1970-01-01
            相关资源
            最近更新 更多