- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在为我们系统的一部分编写数据层,该部分记录有关每天运行的自动化作业的信息 - 作业名称、运行时长、结果等。
我正在使用 Entity Framework 与数据库对话,但我试图对更高级别的模块隐藏这些细节,并且我不希望实体对象本身被暴露。
但是,我想让我的界面在用于查找工作信息的标准方面非常灵活。例如,用户界面应该允许用户执行复杂的查询,例如“给我所有在上午 10:00 到 11:00 之间运行但失败的名为‘hello’的作业”。显然,这看起来像是动态构建的工作 Expression
树。
所以我希望我的数据层(存储库)能够接受类型为 Expression<Func<string, DateTime, ResultCode, long, bool>>
的 LINQ 表达式。 (lambda 表达式)然后在幕后将该 lambda 转换为我的 Entity Framework ObjectContext
的表达式可以用作 Where()
中的过滤器条款。
简而言之,我正在尝试转换 Expression<Func<string, DateTime, ResultCode, long, bool>>
类型的 lambda 表达式至 Expression<Func<svc_JobAudit, bool>>
, 其中svc_JobAudit
是对应于存储作业信息的表的 Entity Framework 数据对象。 (第一个delegate中的四个参数分别对应job的名字,什么时候运行,运行结果,ms中用了多长时间)
我使用 ExpressionVisitor
取得了很好的进展上课,直到我碰壁并收到 InvalidOperationException
出现此错误消息:
When called from 'VisitLambda', rewriting a node of type 'System.Linq.Expressions.ParameterExpression' must return a non-null value of the same type. Alternatively, override 'VisitLambda' and change it to not visit children of this type.
我完全不知所措。为什么它不允许我将引用参数的表达式节点转换为引用属性的节点?还有其他方法吗?
下面是一些示例代码:
namespace ExpressionTest
{
class Program
{
static void Main(string[] args)
{
Expression<Func<string, DateTime, ResultCode, long, bool>> expression = (myString, myDateTime, myResultCode, myTimeSpan) => myResultCode == ResultCode.Failed && myString == "hello";
var result = ConvertExpression(expression);
}
private static Expression<Func<svc_JobAudit, bool>> ConvertExpression(Expression<Func<string, DateTime, ResultCode, long, bool>> expression)
{
var newExpression = Expression.Lambda<Func<svc_JobAudit, bool>>(new ReplaceVisitor().Modify(expression), Expression.Parameter(typeof(svc_JobAudit)));
return newExpression;
}
}
class ReplaceVisitor : ExpressionVisitor
{
public Expression Modify(Expression expression)
{
return Visit(expression);
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof(string))
{
return Expression.Property(Expression.Parameter(typeof(svc_JobAudit)), "JobName");
}
return node;
}
}
}
最佳答案
问题有两个:
我误解了如何访问 Lambda 表达式类型。我仍在返回一个与旧委托(delegate)匹配的 lambda,而不是返回一个与新委托(delegate)匹配的新 lambda。
我需要保留对新 ParameterExpression
实例的引用,但我没有这么做。
新代码如下所示(注意访问者现在如何接受对匹配 Entity Framework 数据对象的 ParameterExpression
的引用):
class Program
{
const string conString = @"myDB";
static void Main(string[] args)
{
Expression<Func<string, DateTime, byte, long, bool>> expression = (jobName, ranAt, resultCode, elapsed) => jobName == "Email Notifications" && resultCode == (byte)ResultCode.Failed;
var criteria = ConvertExpression(expression);
using (MyDataContext dataContext = new MyDataContext(conString))
{
List<svc_JobAudit> jobs = dataContext.svc_JobAudit.Where(criteria).ToList();
}
}
private static Expression<Func<svc_JobAudit, bool>> ConvertExpression(Expression<Func<string, DateTime, byte, long, bool>> expression)
{
var jobAuditParameter = Expression.Parameter(typeof(svc_JobAudit), "jobAudit");
var newExpression = Expression.Lambda<Func<svc_JobAudit, bool>>(
new ReplaceVisitor()
.Modify(expression.Body, jobAuditParameter), jobAuditParameter);
return newExpression;
}
}
class ReplaceVisitor : ExpressionVisitor
{
private ParameterExpression parameter;
public Expression Modify(Expression expression, ParameterExpression parameter)
{
this.parameter = parameter;
return Visit(expression);
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
return Expression.Lambda<Func<svc_JobAudit, bool>>(Visit(node.Body), Expression.Parameter(typeof(svc_JobAudit)));
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof(string))
{
return Expression.Property(parameter, "JobName");
}
else if (node.Type == typeof(DateTime))
{
return Expression.Property(parameter, "RanAt");
}
else if (node.Type == typeof(byte))
{
return Expression.Property(parameter, "Result");
}
else if (node.Type == typeof(long))
{
return Expression.Property(parameter, "Elapsed");
}
throw new InvalidOperationException();
}
}
关于c# - 使用 LINQ ExpressionVisitor 将原始参数替换为 lambda 表达式中的属性引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11164009/
我从 MSDN 上关于 How to: Modify Expression Trees 的文章中得知ExpressionVisitor 应该做什么。它应该修改表达式。 然而,他们的示例非常不切实际,所
我需要在执行之前使用 ExpressionVisitor 来分析表达式。根据我的需要,我需要评估 Divide 表达式的正确部分,但我不知道该怎么做。这是我拥有的示例代码: internal clas
如何使用 olingo4 将原始表达式传递给 Odata4 的 ExpressionVisitor 实现。这就是在 olingo2 JDBC Visitor Filter 中完成的方法 String
我正在尝试在我的 Entity Framework 模型中添加对多语言分类字符串的支持。这是我的: 实体: public partial class ServiceState : ITranslata
我正在关注 example series on MSDN用于创建 LINQ 提供程序并碰壁了。 我希望当我编写以下测试时 ExpressionVisitor下面源代码中的子类是 VisitMethod
我正在关注 this blog尝试为我目前正在处理的项目创建适用于 MSAccess 的 IQueryable 提供程序。 我得到了上面链接的页面,但是有几段代码创建了继承自 ExpressionVi
我正在使用 ExpressionVisitor 解析表达式树以查明它是否包含指定参数。找到参数后,继续遍历就没有意义了。 有什么方法可以停止一般访问者模式的遍历,更具体地说是.NET 中Express
我有一个在数据库中实现软删除的框架(称为 DeletedDate 的可空日期时间)。我正在使用存储库来处理主要实体请求,如下所示: /// /// Returns a Linq Queryable
我正在尝试使用定义明确的模型为定义明确的 Web API 构建 LINQ 提供程序。我正在关注这些演练: Part I Part II 我已经能够创建将表达式转换为所需 URL 的查询提供程序,并且效
我必须为一项任务设计一个解决方案,我想使用理论上类似于 C# 的 ExpressionVisitor 的东西。 出于好奇,我打开了 ExpressionVisitor 的 .NET 源代码来查看它。从
在有人喊出答案之前,请通读问题。 .NET 4.0 的 ExpressionVisitor 方法的目的是什么: public static ReadOnlyCollection Visit(ReadO
我在 Eclipse 中从实体创建表时遇到一些麻烦。这个项目最初是在 Windows 上的 Eclipse 上,我从 mysql 表创建了实体并将其导入到项目中。一切都运转良好。昨天我决定从 Wind
我正在尝试按照 Creating an IQueryable LINQ Provider 上的说明进行操作,但是当我实现从 ExpressionVisitor 继承的类时按照指示,我被告知 Expre
我有一个问题,像这样: var query = from sessions in dataSet where (names.Contains(sessions.
我有一个 ExpressionVisitor我将其添加到 EF Core 的 IQueryable .除 Include 方法外,一切正常。可能是因为他们强制执行您的 IQueryable.Provi
我正在为我们系统的一部分编写数据层,该部分记录有关每天运行的自动化作业的信息 - 作业名称、运行时长、结果等。 我正在使用 Entity Framework 与数据库对话,但我试图对更高级别的模块隐藏
我正在使用 Olingo 框架以 Java 语言实现符合 OData 标准第 4 版的 Web 服务。我需要自定义 $filter 的响应。我已经实现了一个访客 as documented in th
System.Linq.Expressions.ExpressionVisitor 有一个名为 VisitExtension 的方法,它似乎除了在表达式被访问。 protected internal
我是一名优秀的程序员,十分优秀!