2012-10-11 21 views
3

聲明:我在服務/實體/ etc等中將記事本的名稱改爲SO的通用內容。如果您發現類名不一致,請忽略它們,因爲這不是問題。EF不執行數據庫級別的where子句

我正在爲一個客戶端的WCF服務工作,我正在序列化的表達式有一些問題。我目前使用Serialize.Linq來處理表達式序列化。最重要的是,我使用DataContract類在客戶端創建表達式,並使用我的Entity類將其轉換爲表達式。

假設這兩個類:

  1. myEntity所(在項目中DataContract命名空間的一部分)
  2. myEntity所(該項目的實體的命名空間的一部分)

兩者具有相同的特性,然後使用AutoMapper將通過EF獲得的實體轉換爲DataContract對象,然後將該對象發送回客戶端。

爲了應付式變換,我使用的是ExpressionVisitor類:

class MyExpressionVisitor : ExpressionVisitor 
{ 
    public ParameterExpression ParameterExpression { get; private set; } 

    public MyExpressionVisitor(ParameterExpression newParameterExp) 
    { 
     ParameterExpression = newParameterExp; 
    } 

    protected override Expression VisitParameter(ParameterExpression node) 
    { 
     return ParameterExpression; 
    } 

    protected override Expression VisitMember(MemberExpression node) 
    { 
     if (node.Member.DeclaringType == typeof(DataContracts.MyEntity)) 
     { 
      return Expression 
       .MakeMemberAccess(this.Visit(node.Expression), typeof(Entities.MyEntity).GetMember(node.Member.Name).FirstOrDefault()); 
     } 

     return base.VisitMember(node); 
    } 
} 

這是我怎樣,我打電話給我的服務:

Expression<Func<DataContracts.MyEntity, bool>> expression = 
    fl.SomeNameField1 == "John Doe" || fl.SomeNameField2 == "John Doe"; 
var entities = manager.MyService.GetFilteredEntities(expression.ToExpressionNode()); 

這是我目前的服務實現(部分,省略返回線等...)爲GetFilteredEntities

// Using Serialize.Linq for send expressions over WCF. 
// query is an ExpressionNode from the Serialize.Linq library. 
// This DOES NOT execute the where clause on the database. 
var expression = query.ToExpression<Func<DataContracts.MyEntity, bool>>(); 
var visitor = new MyExpressionVisitor(Expression.Parameter(typeof(Entities.MyEntity), expression.Parameters[0].Name)); 
var entityExpression = Expression.Lambda<Func<Entities.MyEntity, bool>>(visitor.Visit(expression.Body), visitor.ParameterExpression); 
var func = entityExpression.Compile(); 
var entities = this.Entities.MyEntities.Where(func); 

全部代碼工作,但Where不適用於數據庫級別,它應用於內存集合每隔行從我的表中。這需要很長時間,因爲表格有150k +行。

如果我硬編碼的地方,我希望能夠在服務,它在數據庫級別應用where子句:

// This DOES execute the where clause on the database. 
var temp1 = this.Entities.MyEntities.Where(fl => fl.SomeNameField1 == "John Doe" || fl.SomeNameField2 == "John Doe"); 

// This DOES execute the where clause on the database. 
Func<Entities.MyEntity, bool> func2 = fl => fl.SomeNameField1 == "John Doe" || fl.SomeNameField2 == "John Doe"; 
var temp2 = this.Entities.MyEntities.Where(func2); 

我知道我可以只寫一堆不同的服務opperations,將允許的用戶可以通過傳入名稱,ids等來進行過濾,但是這個表的列數很少(200+),並且我在所述數據庫上有零輸入。對於可能正在使用我寫的客戶端的其他開發人員來說,使用任何數據創建表達式會更容易,因爲我想可以使用db級別的位置。

我幾乎可以肯定我已經在這篇文章中包含了所有與之相關的內容。我使用SQL Server Profiler來檢查EF正在運行的查詢,這就是我如何知道哪些使用了哪裏。如有需要,請詢問更多信息。

謝謝!

/walloftext

+0

你看動態LINQ的圖書館嗎? http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx – ken

+0

@ken,簡單地(相同的博客文章),但我不希望使用字符串來創建查詢,因爲它更容易,強類型化了我所做的路線。 – Gromer

回答

2

問題也許是這一行:

var func = entityExpression.Compile(); 

既然你打電話Where與編譯委託函數,你是不是叫凡實際被髮送到DB過載。

你需要一個表達式對象傳遞給Where(即調用one of these

+0

呃,就是這樣。我以前沒有像這樣處理過表達式樹,並且正在關注'Serialize.Linq'的例子。真的,非常感謝你!驗證刪除,只是調用'.Where(entityExpression)'。只要SO讓我這麼做,將這個標記爲答案。 – Gromer

0

您是否嘗試過使用LinqKit創建複合查詢?它提供了與PredicateBuilder一起使用表達式的簡單方法。

看看this address,源代碼非常簡單,它在我的情況下創造了奇蹟。

+0

我喜歡'PredicateBuilder',但是據我所知這裏並沒有幫助,主要是因爲我不得不通過WCF序列化。 – Gromer

1

我不認爲你在Where子句中使用它之前,你應該編譯你的表達。這樣做將會調用System.CoreSystem.Linq命名空間提供的擴展方法。你想要的方法超載,需要一個Expression類型的對象。

換句話說,嘗試刪除這一行:

var func = entityExpression.Compile();