我试图编写一个从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;
}
答案 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)。