时间:2011-04-05 00:56:49

标签: asp.net linq linq-to-sql validation reflection

我试图编写一个从CustomValidator调用的方法来确定字符串属性是否唯一。我试图使它通用,以便我可以重用许多不同的字符串属性的代码。我正在使用反射。这看起来像是一种太复杂的方式吗?是否有更好的方法来做到这一点,但仍然是通用的?

public virtual bool IsPropertyUnique(T entity, string newValue, string propertyName)
        {
            var values =
                Context.GetTable<T>.Where(e => string.Equals(e.GetType().GetProperty(propertyName).GetValue(e, null), newValue)).ToList();

            return values.Count == 0;
        }

2 个答案:

答案 0 :(得分:0)

一种可能的改进:

public virtual bool IsPropertyUnique(T entity, string newValue, string propertyName)
{
    var propertyInfo = typeof(t).GetProperty(propertyName);
    return !FindAll()
           .Any(e => string.Equals(propertyInfo.GetValue(e, null), newValue));
}

答案 1 :(得分:0)

由于这是LINQ to SQL,因此您需要提供可以理解并解析为SQL的内容。此刻,它会看到一堆疯狂的反射并开始哭泣。

您可以将方法调用的形式更改为

public Exists(Expression<Func<T, bool>> filter)
{
     return Context.GetTable<T>.Any(filter);
}

// Usage
string valueToCheck = "Boo!";
bool exists = Exists(t => t.Bar == valueToCheck);
if (exists)
{
    return "BAD USER - PICK SOMETHING UNIQUE";
}

这样就可以了。

如果你想保留你的方法签名,你必须使用表达式树来解决问题。基本上你想要创建以下表达式,以便LINQ to SQL可以“哦,是的,这是对应于属性'Bar'的列的where子句”

t => t.Bar == valueToCheck

要重新创建,您需要执行以下操作

private static Expression<Func<T, bool>> GetPredicate(string property, string value)
{
    // First you need a parameter of the correct type
    ParameterExpression parameter = Expression.Parameter(typeof (T), "t");

    // Then use that parameter to access the appropriate property
    MemberExpression propertyToAccess = Expression.Property(parameter, typeof (T), property);

    // Introduce the constant value to check
    ConstantExpression valueToCompare = Expression.Constant(value);

    // Make sure they're equal
    Expression comparison = Expression.Equal(propertyToAccess, valueToCompare);

    // and create the expression based on the method body and the parameter...
    return (Expression<Func<T, bool>>)Expression.Lambda(comparison, parameter);
}

public IsPropertyUnique(T entity, string property, string value)
{
    return !Context.GetTable<T>.Any(GetPredicate(property, value));
}

同样使用Any而不是Where在这里可以稍微提高性能,因为它不需要从DB中加载匹配的记录(它只会做一个IF EXISTS)。