如果你能夠使用通用IQueryable<T>
變異,這將成爲一個更簡單的問題,因爲你不再需要CreateQuery
並可以對直接執行IQueryable<T>
來源。
public static IQueryable<T> WhereLike<T>(this IQueryable<T> source, string propertyName,
string pattern)
{
if (source == null) throw new ArgumentNullException("source");
if (propertyName == null) throw new ArgumentNullException("propertyName");
var a = Expression.Parameter(typeof(T), "a");
var prop = Expression.PropertyOrField(a, propertyName);
var expr = Expression.Call(
typeof(SqlMethods), "Like",
null,
prop, Expression.Constant(pattern));
var lambda = Expression.Lambda<Func<T, bool>>(expr, a);
return source.Where(lambda);
}
注意兩個關鍵點:
而不是僅僅抓住屬性,如果我們使用PropertyOrField我們可以適當支持可以暴露領域的Linq-2-SQL生成的代碼。
另外,由於我們針對IQueryable<T>
源執行,我們需要從我們的「Like」MethodCallExpression
的結果創建lambda表達式。
如果您需要非一般的變種,你仍然可以完成同樣的事情,但你需要換你像MethodCallExpression
在哪裏MethodCallExpression
,以便它被正確的結構:
public static IQueryable WhereLike(this IQueryable source, string propertyName,
string pattern)
{
if (source == null) throw new ArgumentNullException("source");
if (propertyName == null) throw new ArgumentNullException("propertyName");
var a = Expression.Parameter(source.GetType().GetGenericArguments().First(), "a");
var prop = Expression.PropertyOrField(a, propertyName);
var expr = Expression.Call(
typeof(SqlMethods), "Like",
null,
prop, Expression.Constant(pattern));
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { source.ElementType },
source.Expression,
Expression.Lambda(expr, a));
return source.Provider.CreateQuery(whereCallExpression);
}
您可以調用任何使用通配符變種:
var data = source.WhereLike("ColumnName", "%o%");
並不像運營商的SQL只對字符串的工作? – Fran
@Fran爲什麼這很重要? – Servy
@Servy因爲如果他無法確定屬性的類型,他可以嘗試在不支持它的屬性上使用WhereLike(DateTime,Double,....),那麼他會在運行時發生異常它發生。也許他試圖抓住源ElementType並使用反射來查找屬性類型。 – Fran