免责声明:我在记事本中将服务/实体/等的名称更改为 SO 的通用名称。如果您发现类名不一致,请忽略它们,因为这不是问题所在。
我正在为客户开发 WCF 服务,但我在序列化表达式时遇到了一些问题。我目前正在使用 Serialize.Linq处理表达式序列化。最重要的是,我使用我的 DataContract 类在客户端创建表达式,并使用我的实体类将其转换为表达式。
假设这两个类:
- MyEntity(项目中 DataContract 命名空间的一部分)
- MyEntity(项目中 Entities 命名空间的一部分)
两者具有相同的属性,我使用 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);
我知道我可以编写一堆不同的服务操作,允许用户通过传入名称、ID 等进行过滤,但是这个表的列数量多得离谱(200 多个),而我的输入为零在所述数据库上。对于可能正在使用我正在编写的客户端的其他开发人员来说,能够使用他们喜欢的任何数据和列创建表达式要容易得多,所以我喜欢让这个应用在数据库级别。
我几乎可以肯定我已经在这篇文章中包含了所有相关的内容。我使用 SQL Server Profiler 来检查 EF 正在运行的查询,这就是我知道哪些查询在哪里使用的方式。如果需要,请在需要时询问更多信息。
谢谢!
/壁纸
最佳答案
也许问题出在这一行:
var func = entityExpression.Compile();
由于您使用已编译的委托(delegate)函数调用 Where
,因此您没有调用实际发送到 DB 的 Where 的重载。
您需要将表达式对象传递给 Where
(即调用 one of these)
关于c# - EF 不在数据库级别执行 where 子句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12846913/