代码之家  ›  专栏  ›  技术社区  ›  alextansc

linq2sql:如何实现一般的最大字符串长度验证?

  •  2
  • alextansc  · 技术社区  · 15 年前

    linq2sql中的一个常见问题是,.net字符串允许为变量分配任何长度,而您的数据库可能有一个特定的max-length约束(如varchar(5))。这将导致SQL错误消息“字符串或二进制数据将被截断。”,这是非常无用的,因为它没有告诉您哪些字段是罪魁祸首。

    显然,验证最大字符串长度的输入是正确的方法。我面临的主要问题是为我的项目中的每个LINQ对象创建必要的验证,并在更新字段的最大长度时更新验证。

    理想情况下,我需要找到一种方法来动态地确定生成字段的最大长度,这样我就不会忘记稍后更新验证。

    到目前为止,我能找到的最好的实现方法是 "Integrating xVal Validation with Linq-to-Sql" 这已经远远超过了我能想到的任何事情。唯一的不确定点是动态确定最大长度。

    有人看到或执行过类似的事情吗?

    1 回复  |  直到 15 年前
        1
  •  2
  •   Ben M    15 年前

    linq2sql代码生成器在属性字段上放置一个属性,类似于:

    [Column(Storage="_Message", DbType="NVarChar(20)")]
    

    在运行时提取和使用这些信息很简单:

    public class Row
    {
        // normally generated by LINQ2SQL
        [Column(Storage = "_Message", DbType = "NVarChar(20)")]
        public string Message
        {
            get;
            set;
        }
    
        // normally generated by LINQ2SQL
        [Column(Storage = "_Property", DbType = "NVarChar(20) NOT NULL")]
        public string Property
        {
            get;
            set;
        }
    }
    
    public class VarCharInfo
    {
        public int? MaxLen;
        public bool IsNullable;
    }
    
    public static VarCharInfo GetVarCharInfo(PropertyInfo propertyInfo)
    {
        var attrib = propertyInfo.GetCustomAttributes(typeof(ColumnAttribute), false)
            .OfType<ColumnAttribute>()
            .FirstOrDefault();
    
        if (attrib == null || attrib.DbType == null)
        {
            return null;
        }
    
        var match = Regex.Match(attrib.DbType, @"VarChar\((?'len'\d+)\)(?'notnull' NOT NULL)?");
    
        if (!match.Success)
        {
            return null;
        }
    
        var rvl = new VarCharInfo();
    
        rvl.MaxLen = int.Parse(match.Groups["len"].Captures[0].Value);
        rvl.IsNullable = match.Groups["notnull"].Success;
    
        return rvl;
    }
    
    public static bool ValidateVarCharColumns(object dataObject)
    {
        bool success = true;
    
        foreach (var propertyInfo in dataObject.GetType()
            .GetProperties()
            .Where(pi => pi.PropertyType == typeof(string)))
        {
            var vci = GetVarCharInfo(propertyInfo);
    
            if (vci != null)
            {
                var currentValue = propertyInfo.GetGetMethod()
                    .Invoke(dataObject, null) as string;
    
                if (currentValue == null)
                {
                    if (!vci.IsNullable)
                    {
                        // more work: value is null but it shouldn't be
                        success = false;
                    }
                }
                else if (vci.MaxLen != null && currentValue.Length > vci.MaxLen)
                {
                    // more work: value is longer than db allows
                    success = false;
                }
            }
        }
    
        return success;
    }
    
    static void UsageTest()
    {
        Row t = new Row();
        t.Message = "this message is longer than 20 characters";
        // t.Property is null
    
        ValidateVarCharColumns(t);  // returns false!
    }