使用Attribute进行实体数据校验

接上篇接手同事代码,新增新的业务类型。每种类型都存到新的数据库表中。

有这么个需求,假设业务类型为A,数据表为Table_A,那么就有一张Table_VerifyA表,用于录入A的字段校验信息。

看到同事代码的一瞬间,我再次崩溃了,以下是大致的逻辑

foreach (var pi in typeof(Table_A).GetProperties()) {
    if (...) {
       ...
   } else {
       ...
   }
   if (...) {
       ...
   }
    foreach (var p2 in typeof(Table_VerifyA).GetProperties()) {
        if (...) {
            ...
        } else {
            ...
        }
        if (...) {
            ...
        }
    }
}

大致看了下,一个业务表大概有100个字段,800行的ifelse,有够暴力的。。

思考(摸鱼)了一天后,有了点想法

我可以通过Attribute来控制当前字段是否需要校验以及校验方式,所以就有了下面的东西。

  • 首先需要一个接口 IVerify
/// <summary>
/// 根据字段具体值,初始化校验方法
/// </summary>
/// <param name="value">字段的值</param>
void BuildVerifyRule(object value);
/// <summary>
/// 校验方法
/// </summary>
/// <param name="value">需要校验的值</param>
/// <param name="msg">错误信息</param>
/// <returns>是否通过校验</returns>
bool Test(object value, out string msg);
  • 实现IVerify的Attribute,例如最小值的判断
public class MinLimitVerifyAttribute : BaseVerify, IVerify {
    private int? _min;
    public void BuildVerifyRule(object value) {
        var p = CheckValue(value);
        if (int.TryParse(p, out int m)) {
            _min = m;
        }
    }
    public bool Test(object value, out string msg) {
        var m = "";
        var result = CheckInput(value, input => {
            if (int.TryParse(input, out int i)) {
                if (_min.HasValue) {
                    var r = i >= _min;
                    m = r ? "" : $"数值不匹配!(必须大于等于{_min.Value})";
                    return r;
                } else {
                    m = "车型库数据非法!";
                    return false;
                }
            } else {
                m = "非数值!";
                return false;
            }
        });
        msg = m;
        return result;
    }
}
  • Table_VerifyA的实体表上使用Attribute
[MinLimitVerify]
public string AAAA { get; set; }
  • 提供一个调用方式
 public class VerifyTool {
    Dictionary<string, IVerify> verifies = new Dictionary<string, IVerify>();
    public VerifyTool SetRule<T>(T stand) where T : IStandard {
        var props = typeof(T).GetProperties();
        foreach (PropertyInfo prop in props) {
            var attr = prop.GetAttribute<IVerify>();
            if (attr == null)
                continue;
            var value = prop.GetValue(stand, null);
            attr.BuildVerifyRule(value);
            verifies.Add(prop.Name, attr);
        }
        return this;
    }
    public bool Verify(object entity, out string msg) {
        var props = entity.GetType().GetProperties();
        foreach (PropertyInfo prop in props) {
            var name = prop.Name;
            var rename = prop.GetAttribute<VerifyNameAttribute>();
            var desprition = prop.GetAttribute<DescriptionAttribute>();
            if (rename != null)
                name = rename.Name;
            if (!verifies.ContainsKey(name))
                continue;
            var vf = verifies[name];
            var value = prop.GetValue(entity, null);
            if (!vf.Test(value, out string err)) {
                var desp = desprition?.Description ?? name;
                msg = $"{desp}:{err}";
                return false;
            }
        }
        msg = "";
        return true;
    }
}
  • 最后调用
if (!verifyTool.SetRule(stand).Verify(entity, out msg)) {
    throw new Exception(msg);
}
posted @ 2021-04-19 09:36  yaoqinglin_mtiter  阅读(128)  评论(0编辑  收藏  举报