简体   繁体   English

使用表达式<func>在表达式内<func></func></func>

[英]Use an Expression<Func> within an Expression<Func>

The below code works fine (throws no translation error):下面的代码工作正常(不引发翻译错误):

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() and IsLessThan() are methods that have been registered in OnModelCreating(ModelBuilder builder) from dbContext, as explained in this answer . IsGreaterThan()IsLessThan()是已在 dbContext 的OnModelCreating(ModelBuilder builder)中注册的方法,如本答案中所述。 So the problem is not with those methods.所以问题不在于这些方法。

The below code doesn't work:下面的代码不起作用:

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();

It throws the below error.它引发以下错误。

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().

I understand why it fails.我明白为什么会失败。 Expression<Func<>>.Compile() returns a Func<> and those cannot be used in Linq to Sql. Expression<Func<>>.Compile()返回一个Func<>并且不能在 Linq 到 Sql 中使用。 So I've been looking for workarounds.所以我一直在寻找解决方法。

The most promising I found is from this answer .我发现的最有希望来自这个答案 It worked as expected in the fiddle he provided, but for some reason, it didn't work for me.它在他提供的小提琴中按预期工作,但由于某种原因,它对我不起作用。 My code after implementing his 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();

Is there some other way to nest Expression<Func<>> s?还有其他方法可以嵌套Expression<Func<>> s吗?

EDIT : As mentioned by @pinkfloydx33:编辑:正如@pinkfloydx33 所述:

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

should have been:本来应该:

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

Funny enough, I make this same mistake with string.Replace() a loooot.有趣的是,我在string.Replace()中犯了同样的错误。 It works fine now after this.在此之后它现在工作正常。

This feature is not supported by EF, and i don't know why;) You have to install LINQKit and use AsExpandable() adn Invoke instead of Compile : 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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM