2015-02-05 337 views
1

我正在創建一個IQueryable,我想用於傳遞給實體框架的查詢。我的存儲庫不公開可查詢。IQueryable表達式翻譯

var query = new List<Entity>().AsQueryable().Where(x => x.Property == "argument"); 

我在我的存儲庫上有一個方法,將採用IQueryable。

如何使用相同的查詢來查詢我的DbSet?我試圖從查詢中提取表達式來爲dbset構建一個新的表達式。以下是我有這麼遠,但它不工作:

public IDbSet<TEntity> DbSet { get; set; } 

public IEnumerable<TEntity> Find(IQueryable<TEntity> queryable) 
{ 
     var parameter = Expression.Parameter(typeof (TEntity)); 
     var body = queryable.Expression; 

     var lambda = Expression.Lambda<Func<TEntity, bool>>(body, parameter); 
     var result = DbSet.Where(lambda); 
     return null; 
} 

的代碼時,我嘗試失敗,並出現以下錯誤創建拉姆達:類型 表達「System.Linq.IQueryable`1 [MyTEntity] '不能用於返回類型'System.Boolean'

我顯然沒有正確地構建表達式,我錯過了什麼?有沒有更簡單的方法來做我想要完成的事情?

另外我見過一些示例顯示錶達式應該有一個參數屬性。但是不管我輸入什麼類型的表達式類型,這個是ConstantExpression,我都沒有看到IQueryable.Expression的參數屬性。

+2

更簡單的界面,我建議將'公開名單查找(表達式>過濾器){返回DbSet.Where(過濾器) .ToList(); }'。 (也許加入'AsNoTracking()')。這將允許將它用作Find(x => x.Property ==「argument」)'。不過,我猜你對當前的設計有理由。你能解釋一下你想要完成的事情嗎?我沒有做過充分的工作? – hvd 2015-02-05 23:41:05

+0

這是一個好主意,我可以使用它,但這就是爲什麼我使用了我的原創設計。該存儲庫基於域級別的實體。我實際上在客戶端查詢的對象,通過基於數據合同的服務層。我的服務Find方法需要一個Queryable ,我使用automapper將它投影到域級別的TEntity。我希望在客戶端上有一個查詢,如下所示:var query = new List ()。AsQueryable()。Where(...)service.Find(query)這就是解釋,好的或壞的設計,我還沒有決定。 – twifosp 2015-02-05 23:48:34

+0

我想我有什麼辦法,我需要從查詢中獲取參數。由於我投射我的領域模型,我沒有看到沒有IQueryable的清晰路徑。我只需要一種方法來接受一個iqueryable並從其表達式樹中構建lambda表達式。 – twifosp 2015-02-06 02:17:11

回答

2

在你的情況下,queryable.Expression代表整個表達Queryable.Where(constantList, x => x.Property == "argument")。如果你只想要Where() lambda,你需要提取它。要做到這一點,你可以使用這樣的代碼:

public IEnumerable<TEntity> Find<TEntity>(IQueryable<TEntity> queryable) 
{ 
    var methodCall = queryable.Expression as MethodCallExpression; 
    Func<IQueryable<TEntity>, Expression<Func<TEntity,Boolean>>, IQueryable<TEntity>> whereDelegate = Queryable.Where; 

    if (methodCall.Method == whereDelegate.Method 
     && methodCall.Arguments[0] is ConstantExpression) 
    { 
     var whereLambdaQuote = (UnaryExpression)methodCall.Arguments[1]; 
     var whereLambda = (Expression<Func<TEntity, bool>>)whereLambdaQuote.Operand; 

     var result = DbSet.Where(whereLambda); 
    } 

    return null; 
}