我有一个简单的linq-to-sql语句,它将string[]
中的值与表中的值进行匹配,并返回匹配的表值。
_table
属于System.Data.Linq.Table<TEntity>
类型
public IEnumerable<ZipCode> match(IEnumerable<string> values) {
HashSet<string> valueSet = new HashSet<string>(values);
return _table.Where(x => valueSet.Contains(x.zipcode);
}
我如何重构它,以便将要使用的字段传递到Contains()
?
我失败的尝试:
public IEnumerable<ZipCode> match<T>(IEnumerable<T> values,
Expression<Func<ZipCode, T>> field) {
HashSet<T> valueSet = new HashSet<T>(values);
return _table.Where(x => valueSet.Contains(field(x)));
}
这会产生错误:
方法的系统。对象DynamicInvoke(System.Object[])"不支持转换为SQL。
我的想法是,我可以使用表达式树来为Contains()
提供字段,但我不知道这是如何或是否是正确的表达式使用方式。也许有一个更好的解决方案。
我能够使用以下内容(在.NET 4.5中,但我相信它在早期版本中会起作用)
static IEnumerable<TTable> Match<TTable, TField>(IQueryable<TTable> table, IEnumerable<TField> values, Expression<Func<TTable, TField>> fieldSelector)
{
var valuesConstant = Expression.Constant(values.Distinct());
var callContains = Expression.Call(typeof(Enumerable), "Contains", new[] { typeof(TField) }, new Expression[] { valuesConstant, fieldSelector.Body });
var whereExpression = Expression.Lambda<Func<TTable, bool>>(callContains, (fieldSelector.Body as MemberExpression).Expression as ParameterExpression);
return table.Where(whereExpression);
}
您应该能够删除我使用的表参数,并使用您拥有的成员变量。
使用Func<ZipCode, T> field
:而不是Expression<Func<ZipCode, T>> field
public IEnumerable<ZipCode> match<T>(IEnumerable<T> values, Func<ZipCode, T> field)
{
HashSet<T> valueSet = new HashSet<T>(values);
return _table.Where(x => valueSet.Contains(field(x)));
}