【问题标题】:Use an Expression<Func> within an Expression<Func>在 Expression<Func> 中使用 Expression<Func>
【发布时间】: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&lt;Func&lt;&gt;&gt;.Compile() 返回一个 Func&lt;&gt; 并且不能在 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&lt;Func&lt;&gt;&gt;s吗?

编辑:正如@pinkfloydx33 所述:

where.Replace(() => keyFunc, key);

应该是:

where = where.Replace(() => keyFunc, key);

很有趣,我在string.Replace() 上犯了同样的错误。 在此之后它现在可以正常工作了。

【问题讨论】:

  • 我不相信 EF 支持嵌套表达式...对您想要构建的最终结果进行一些澄清可能会有所帮助...
  • 顺便说一句...在您尝试表达式访问者的示例代码中,您没有重新分配 where 变量。表达式是不可变的。所以你需要where = where.Replace(...) 并且访问者应该工作
  • @pinkfloydx33 啊……这就是缺少的东西!!谢谢!

标签: c# entity-framework linq


【解决方案1】:

EF 不支持此功能,我不知道为什么;) 您必须安装 LINQKit 并使用 AsExpandable()Invoke 而不是 Compile

string refId = "refId";
Expression<Func<Tin, string>> key = obj => obj.Id;
bool forward = true;
IQueryable<Tin> q = queryable
  .AsExpandable()
  .Where(o => forward ? key.Invoke(o).IsGreaterThan(refId) : key.Invoke(o).IsLessThan(refId));
var x = await q.ToArrayAsync();

【讨论】:

  • 谢谢你。我宁愿不为这种情况安装库。但这看起来更干净。我想知道我现在拥有的解决方案的性能。如果我必须经常做这个表达式嵌套,我可能会改用这个。
  • 其实更接近这些库。你所做的与他们所能做的相比毫无意义:github.com/hazzik/DelegateDecompilergithub.com/axelheer/nein-linq
猜你喜欢
  • 2019-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多