我正在为我们系统的一部分编写数据层,该数据层记录有关每天运行的自动作业的信息 - 作业名称,运行时间,结果,等等.
我正在使用Entity Framework与数据库交谈,但我试图将这些细节隐藏在更高级别的模块之外,我不希望实体对象本身被暴露.
但是,我想使我的界面在用于查找作业信息的标准中非常灵活.例如,用户界面应允许用户执行复杂的查询,例如"给我所有名为'hello'的作业,该作业在上午10:00到11:00之间运行失败." 显然,这看起来像是动态构建Expression树的工作.
所以我希望我的数据层(存储库)能够接受类型Expression<Func<string, DateTime, ResultCode, long, bool>>(lambda表达式)的LINQ表达式,然后在后台将该lambda转换为我的实体框架ObjectContext可以用作Where()子句中的过滤器的表达式.
简而言之,我正在尝试将类型的lambda表达式转换Expression<Func<string, DateTime, ResultCode, long, bool>>为Expression<Func<svc_JobAudit, bool>>,其中svc_JobAuditEntity Framework数据对象对应于存储作业信息的表.(第一个委托中的四个参数分别对应于作业名称,运行时间,结果以及分别在MS中花费的时间)
我在使用该ExpressionVisitor课程时取得了很好的进展,直到我碰到了一堵砖墙并收到了一条InvalidOperationException错误消息:
从"VisitLambda"调用时,重写"System.Linq.Expressions.ParameterExpression"类型的节点必须返回相同类型的非null值.或者,覆盖"VisitLambda"并将其更改为不访问此类型的子项.
我完全不知所措.为什么它不允许我将引用参数的表达式节点转换为引用属性的节点?还有另一种方法可以解决这个问题吗?
以下是一些示例代码:
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>> …Run Code Online (Sandbox Code Playgroud) 如果我有一个函数委托的表达式,它接受许多参数,如下所示:
Expression<Func<int, int, int, bool>> test = (num1, num2, num3) => num1 + num2 == num3;
Run Code Online (Sandbox Code Playgroud)
是否有一种方式/如何替换其中一个值(比如5 num1)并获得等效表达式:
Expression<Func<int, int, bool>> test = (num2, num3) => 5 + num2 == num3;
Run Code Online (Sandbox Code Playgroud)
编辑:
还需要解决复杂类型,例如:
Expression<Func<Thing, int, int>> test = (thing, num2) => thing.AnIntProp + num2;
Run Code Online (Sandbox Code Playgroud) 我试图将lambda表达式中的参数类型从一种类型替换为另一种类型.
我在stackoverflow上找到了其他答案,即这个,但我没有运气.
想象一下你有一个域对象和一个存储库,你可以从中检索域对象.
但是,存储库必须处理自己的数据传输对象,然后映射并返回域对象:
ColourDto.cs
public class DtoColour {
public DtoColour(string name)
{
Name = name;
}
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
DomainColour.cs
public class DomainColour {
public DomainColour(string name)
{
Name = name;
}
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
Repository.cs
public class ColourRepository {
...
public IEnumerable<DomainColour> GetWhere(Expression<Func<DomainColour, bool>> predicate)
{
// Context.Colours is of type ColourDto
return Context.Colours.Where(predicate).Map().ToList();
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,这将不起作用,因为谓词是针对域模型的,而存储库中的Collection是数据传输对象的集合.
我试图使用an ExpressionVisitor来做到这一点,但无法弄清楚如何只更改ParameterExpression没有例外被抛出的类型,例如:
测试场景
public class ColourRepository …Run Code Online (Sandbox Code Playgroud) 我正在尝试构建一个表达式树,我可以将它输入到 Linq2SQL 中,以便它生成一个漂亮的干净查询。我的目的是构建一个过滤器,将任意一组单词与 AND 和 NOT(或 OR 和 NOT)放在一起。因为我想改变我搜索的字段,所以我最好Expresssion<Func<T, string, bool>>通过调用各种辅助函数来组合一个's列表(其中 T 是我正在操作的实体)。然后我会收到一组单词并循环遍历它们并构建一个Expresssion<Func<T, bool>>up(在必要时否定某些表达式),我最终可以将其提供给 .Where 语句。
我一直在使用 LINQKit PredicateBuilder但这段代码处理单参数表达式。然而,它为我自己的尝试提供了一些基础。我的目标是做这样的事情:
var e = (Expression<Func<Entity, string, bool>>)((p, w) => p.SomeField.ToLower().Contains(w));
var words = new []{"amanda", "bob"};
var expr = (Expression<Func<Entity, bool>>)(p => false);
// building up an OR query
foreach(var w in words) {
var w1 = w;
>>>>expr = Expression.Lambda<Func<Entity, bool>>(Expression.OrElse(expr.Body, (Expression<Func<Entity, bool>>)(p => e(p, w))));
}
var filteredEntities = table.Where(expr);
Run Code Online (Sandbox Code Playgroud)
但是由于我使用的是表达式,所以用 >>>> 标记的行显然是非法的(不能e(p, w) …
如何制作通用的辅助方法,以将Func使用的类型从表达式中的一种类型转换为另一种类型
我有一个Expression<Func<IEmployee, bool>>,我想将其转换为
Expression<Func<Employee, bool>>.
Run Code Online (Sandbox Code Playgroud)
第二个类型始终实现第一个类型。一个通用的解决方案是我要实现的目标。
编辑
我已对问题进行了更清晰的编辑。