【发布时间】:2021-02-10 04:08:27
【问题描述】:
下面的代码运行良好(没有翻译错误):
string text = "someString";
string refId = "refId";
bool forward = true;
IQueryable<Tin> q = queryable.Where(o => forward ? text.IsGreaterThan(refId) : text.IsLessThan(refId));
var x = await q.ToArrayAsync();
IsGreaterThan() 和 IsLessThan() 是已从 dbContext 注册到 OnModelCreating(ModelBuilder builder) 的方法,如 this answer 中所述。所以问题不在于这些方法。
下面的代码不起作用:
string refId = "refId";
Expression<Func<Tin, string>> key = obj => obj.Id;
bool forward = true;
IQueryable<Tin> q = queryable.Where(o => forward ? key.Compile()(o).IsGreaterThan(refId) : key.Compile()(o).IsLessThan(refId));
var x = await q.ToArrayAsync();
它会抛出以下错误。
System.InvalidOperationException: The LINQ expression 'DbSet<Follow>
.Where(f => f.FollowerId == __userId_0)
.Where(f => Invoke(__Compile_1, f[Follow])
.IsGreaterThan(__refId_2))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
我明白它为什么会失败。 Expression<Func<>>.Compile() 返回一个 Func<> 并且不能在 Linq to Sql 中使用。所以我一直在寻找解决方法。
我发现的最有前途的是来自this answer。它在他提供的小提琴中按预期工作,但由于某种原因,它对我不起作用。 实现他的答案后我的代码:
string refId = "refId";
Expression<Func<Tin, string>> key = obj => obj.Id;
bool forward = true;
Func<Tin, string> keyFunc = key.Compile();
Expression<Func<Tin, bool>> where = o => forward ? keyFunc(o).IsGreaterThan(refId) : keyFunc(o).IsLessThan(refId);
where.Replace(() => keyFunc, key);
IQueryable<Tin> q = queryable.Where(where);
var x = await q.ToArrayAsync();
还有其他方法可以嵌套Expression<Func<>>s吗?
编辑:正如@pinkfloydx33 所述:
where.Replace(() => keyFunc, key);
应该是:
where = where.Replace(() => keyFunc, key);
很有趣,我在string.Replace() 上犯了同样的错误。
在此之后它现在可以正常工作了。
【问题讨论】:
-
我不相信 EF 支持嵌套表达式...对您想要构建的最终结果进行一些澄清可能会有所帮助...
-
顺便说一句...在您尝试表达式访问者的示例代码中,您没有重新分配
where变量。表达式是不可变的。所以你需要where = where.Replace(...)并且访问者应该工作 -
@pinkfloydx33 啊……这就是缺少的东西!!谢谢!
标签: c# entity-framework linq