2011-01-24 35 views
3

我想在我們的存儲庫中添加一個檢查,用於篩選companyId上的所有對象,如果它匹配給定的值。如何包含一個And()表達式,用於檢查Property和它的值

所以,我們有:

public T First<T>(Expression<Func<T, bool>> expression) where T : EntityObject 
{ 
    var set = GetObjectSet<T>(); 
    return set.FirstOrDefault<T>(); 
} 

我想補充線,看起來是在那裏...

express.And("Check for CompanyId property if it exists then make sure it = 3"); 

如何去這個任何想法?
謝謝:)

回答

4

如果你正在尋找您可以使用對公司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 
    } 
} 
+0

哇,這看起來很有趣!你認爲它也適用於LINQ to Entities?例如:使用`CheckPropertyIfExists`作爲`FirstOrDefault`上的謂詞,這可以在LINQ to Entities中工作嗎? (我的理解是,謂詞必須可以轉換爲SQL語句,並且我只能在謂詞內部使用「規範函數」,但我不太清楚所有這些細節。) – Slauma 2011-01-24 23:46:59

+0

是的,我測試過了它和它與LINQ to Entities一起工作。它也應該與LINQ to SQL一起工作。它仍然可以轉換爲SQL語句,因爲它不會引入任何不會出現在任何簡單的where子句中的東西。儘管它仍然受到與L2E相同的規則約束,即它不會與`enum`值一起工作。 – 2011-01-24 23:58:30

0

Bennor, 非常感謝您的職位是非常有用的。

我把你放在那裏,並創建一個擴展方法,將'And'過濾器附加到現有表達式。

public static Expression<Func<T, bool>> AddEqualityCheck<T, TProperty>(this Expression<Func<T, bool>> expression, string propertyName, TProperty propertyValue) 
    { 
     Type type = typeof(T); 
     var property = type.GetProperty(
      propertyName, 
      BindingFlags.Instance | BindingFlags.Public, 
      null, 
      typeof(TProperty), 
      Type.EmptyTypes, 
      null 
     ); 

     if (property == null || !property.CanRead) 
     { 
      return expression; 
     } 
     else 
     { 
      var equalityExpression = Expression.Equal(
       Expression.MakeMemberAccess(expression.Parameters[0], property), 
       Expression.Constant(propertyValue) 
       ); 
      var andEqualityExpression = Expression.And(equalityExpression, expression.Body); 
      return expression.Update(andEqualityExpression, expression.Parameters); 
     } 
    } 
1

看起來像一個很好的候選人接口,用於從反射遠離:

public interface ICompanyFilterable 
{ 
    int CompanyId { get; set; } 
} 

public partial class YourEntity : ICompanyFilterable 
{ 
    .... 
} 

public static IQueryable<T> FilterByCompanyId<T>(this IQueryable<T> query, int companyId) 
    where T : ICompanyFilterable 
{ 
    return query.Where(e => e.CompanyId == companyId); 
} 
相關問題