LINQ2SQL:如何实现通用的最大字符串长度验证?

时间:2009-07-23 14:39:44

标签: linq-to-sql validation

LINQ2SQL中的一个常见问题是.NET String允许为其变量分配任何长度,而您的数据库可能具有特定的最大长度约束(如VARCHAR(5))。这将导致SQL错误消息“字符串或二进制数据将被截断。”,这是非常无益的,因为它不会告诉您哪些字段是罪魁祸首。

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

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

到目前为止我能找到的最好的实现是"Integrating xVal Validation with Linq-to-Sql",这已经远远优于我能想到的任何东西。唯一不确定的点是动态确定最大长度。

有没有人见过或实施过类似的东西?

1 个答案:

答案 0 :(得分:2)

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!
}