聲明:我在服務/實體/ etc等中將記事本的名稱改爲SO的通用內容。如果您發現類名不一致,請忽略它們,因爲這不是問題。EF不執行數據庫級別的where子句
我正在爲一個客戶端的WCF服務工作,我正在序列化的表達式有一些問題。我目前使用Serialize.Linq來處理表達式序列化。最重要的是,我使用DataContract類在客戶端創建表達式,並使用我的Entity類將其轉換爲表達式。
假設這兩個類:
- myEntity所(在項目中DataContract命名空間的一部分)
- 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
你看動態LINQ的圖書館嗎? http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx – ken
@ken,簡單地(相同的博客文章),但我不希望使用字符串來創建查詢,因爲它更容易,強類型化了我所做的路線。 – Gromer