如果你正在尋找您可以使用對公司ID檢查你的表情釘如果在實體存在公司ID的功能,這應該做的伎倆:
public static Expression<Func<T, bool>> CheckPropertyIfExists<T, TProperty>(Expression<Func<T, bool>> expression, string propertyName, TProperty propertyValue)
{
Type type = typeof(T);
var property = type.GetProperty(propertyName, typeof(TProperty));
if(property == null || !property.CanRead)
return expression;
return expression.Update(
Expression.And(// &&
Expression.Equal(// ==
Expression.MakeMemberAccess(expression.Parameters[0], property), // T parameter.{propertyName}
Expression.Constant(propertyValue) // specified propertyValue constant
),
expression.Body // Original expression
),
expression.Parameters
);
}
你可以使用這樣的:
public T First<T>(Expression<Func<T, bool>> expression, int companyId)
{
var set = GetObjectSet<T>();
return set.FirstOrDefault<T>(CheckPropertyIfExists(expression, "CompanyId", companyId));
}
現在你可以用你的表情,你想,以濾除companyId打電話給你First
方法。
稍微更好的方式來做到這一點可能是使用它作爲過濾方法,即,重寫爲不需要內表達並在對象查詢工作(或IQueryable的)的擴展方法:
public static ObjectQuery<T> FilterByPropertyIfExists<T, TProperty>(this ObjectQuery<T> query, string propertyName, TProperty propertyValue)
{
Type type = typeof(T);
var property = type.GetProperty(propertyName, typeof(TProperty));
if(property == null || !property.CanRead)
return query;
var parameter = Expression.Parameter(typeof(T), "x");
Expression<Func<T, bool>> predicate = (Expression<Func<T, bool>>)Expression.Lambda(
Expression.Equal(// ==
Expression.MakeMemberAccess(parameter, property), // T parameter.{propertyName}
Expression.Constant(propertyValue) // specified propertyValue constant
),
parameter
);
return query.Where(predicate);
}
這樣做的好處在於它可以很好地與標準的LINQ語法(查詢和流暢)結合使用。
例如它允許查詢像這樣:
from x in repository.Clients.FilterByPropertyIfExists("Company", 5)
where x == ???
select x.Name;
[編輯]
我清理了一下,參數上增加知名度的支票(必須是公共的,靜態屬性),以及一個的ObjectQuery實現(將自動使用的ObjectQuery和對象集):
public static class QueryExtensions
{
public static IQueryable<T> FilterByPropertyIfExists<T, TProperty>(this IQueryable<T> query, string propertyName, TProperty propertyValue)
{
Type type = typeof(T);
var property = type.GetProperty(
propertyName,
BindingFlags.Instance | BindingFlags.Public, // Must be a public instance property
null,
typeof(TProperty), // Must be of the correct return type
Type.EmptyTypes, // Can't have parameters
null
);
if (property == null || !property.CanRead) // Must exist and be readable
return query; // Return query unchanged
// Create a predicate to pass to the Where method
var parameter = Expression.Parameter(typeof(T), "it");
Expression<Func<T, bool>> predicate = (Expression<Func<T, bool>>)Expression.Lambda(
Expression.Equal(// ==
Expression.MakeMemberAccess(parameter, property), // T parameter.{propertyName}
Expression.Constant(propertyValue) // specified propertyValue constant
),
parameter
);
return query.Where(predicate); // Filter the query
}
public static ObjectQuery<T> FilterByPropertyIfExists<T, TProperty>(this ObjectQuery<T> query, string propertyName, TProperty propertyValue)
{
var filteredQuery = FilterByPropertyIfExists((IQueryable<T>)query, propertyName, propertyValue);
return (ObjectQuery<T>)filteredQuery; // Cast filtered query back to an ObjectQuery
}
}
哇,這看起來很有趣!你認爲它也適用於LINQ to Entities?例如:使用`CheckPropertyIfExists`作爲`FirstOrDefault`上的謂詞,這可以在LINQ to Entities中工作嗎? (我的理解是,謂詞必須可以轉換爲SQL語句,並且我只能在謂詞內部使用「規範函數」,但我不太清楚所有這些細節。) – Slauma 2011-01-24 23:46:59
是的,我測試過了它和它與LINQ to Entities一起工作。它也應該與LINQ to SQL一起工作。它仍然可以轉換爲SQL語句,因爲它不會引入任何不會出現在任何簡單的where子句中的東西。儘管它仍然受到與L2E相同的規則約束,即它不會與`enum`值一起工作。 – 2011-01-24 23:58:30