是否可以将LINQ查询的一部分放在函数中?

发布于 2025-02-06 04:33:12 字数 931 浏览 2 评论 0原文

基本上,我有一个数据库查询,其中包含许多内容,其中我想在函数中创建这些内容。我只是不能让它工作。非常简单的示例:

// _context is the DatabaseContext
var tmp = _context.Person.Where(p => p.Surname.Contains("Ai"));
tmp = tmp.Where(p => SomeFunction(p));
var res = tmp.ToList();

函数看起来像这样:

private bool SomeFunction(Person p)
{
    return p.IsFemale;
}

这会引发异常:

The LINQ expression 'DbSet<Person>
    .Where(p => p.Surname.Contains("Ai"))
    .Where(p => MyController.SomeFunction(p))' 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(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

是的,当我调用'tmp.tolist()'首先调用'tmp.tolist()',但随后将其内存过滤,我想要的是扩展查询在数据库上。

这可能吗?如果是的话,怎么办?

Basically, I have a Database query with a lot of stuff in a WHERE clause, which I want to create in a function. I just cant get it to work. Very simple example:

// _context is the DatabaseContext
var tmp = _context.Person.Where(p => p.Surname.Contains("Ai"));
tmp = tmp.Where(p => SomeFunction(p));
var res = tmp.ToList();

and the function looks like this:

private bool SomeFunction(Person p)
{
    return p.IsFemale;
}

And this throws an exception:

The LINQ expression 'DbSet<Person>
    .Where(p => p.Surname.Contains("Ai"))
    .Where(p => MyController.SomeFunction(p))' 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(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

Yes, it works when I call 'tmp.ToList()' first but then it will be filtered in-memory, what I want is to extend the query on the database.

Is this possible? How can it be done, if so?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

上课铃就是安魂曲 2025-02-13 04:33:12

您可以构建一个表达式并传递:

public static Expression<Func<Person, bool>> SomeCondition()
{
    return BuildFilter<Person>(p => p.IsFemale);
}

private static Expression<Func<T, bool>> BuildFilter<T>(Expression<Func<T, bool>> expression)
{
    return expression;
}

buildFilter方法将使您的lambda转换为表达树。然后,您可以这样使用它:

.Where(SomeCondition());

如果您想这样做,就有一种更复杂的方法来构建表达式:

public Expression<Func<Person, bool>> SomeCondition()
{
    var parameterExpression = Expression.Parameter(typeof(Person));
    var accessExpression = Expression.Property(parameterExpression, nameof(Person.IsFemale));
    var equalityExpression = Expression.Equal(accessExpression, Expression.Constant(true));
    return Expression.Lambda<Func<Person, bool>>(equalityExpression, parameterExpression);
}

但是我认为在这种情况下,第一种方法更容易阅读和理解。

You could build an expression and pass that:

public static Expression<Func<Person, bool>> SomeCondition()
{
    return BuildFilter<Person>(p => p.IsFemale);
}

private static Expression<Func<T, bool>> BuildFilter<T>(Expression<Func<T, bool>> expression)
{
    return expression;
}

The BuildFilter method will transform your lambda into an expression tree. You could then use it like this:

.Where(SomeCondition());

There is a more complicated way to build the expression if you wish to go that way:

public Expression<Func<Person, bool>> SomeCondition()
{
    var parameterExpression = Expression.Parameter(typeof(Person));
    var accessExpression = Expression.Property(parameterExpression, nameof(Person.IsFemale));
    var equalityExpression = Expression.Equal(accessExpression, Expression.Constant(true));
    return Expression.Lambda<Func<Person, bool>>(equalityExpression, parameterExpression);
}

But I think in this case, the first approach is much easier to read and understand.

吃兔兔 2025-02-13 04:33:12

EF与表达式树一起使用以创建查询,并且无法将方法调用转换为某些SQL,该SQL将在DB中执行(不在内存中)。

您可以将方法重写为此:

private IQueryable<Person> WhereFemale(IQueryable<Person> query)
{
    return query.Where(p => p.IsFemale);
}

然后:

var tmp = _context.Person.Where(p => p.Surname.Contains("Ai"));
tmp = WhereFemale(tmp);
var res = tmp.ToList();

另一种方法 - 您可以创建扩展方法:

public static IQueryable<Person> WhereFemale(this IQueryable<Person> query)
{
    return query.Where(p => p.IsFemale);
}

现在您可以使用方法链:

var res = _context.Person
    .Where(p => p.Surname.Contains("Ai"))
    .WhereFemale(tmp)
    .ToList();

The EF works with Expression trees to create queries and it can't translate method call to some SQL which will be executed in DB (not in memory).

You can rewrite your method to this:

private IQueryable<Person> WhereFemale(IQueryable<Person> query)
{
    return query.Where(p => p.IsFemale);
}

and then:

var tmp = _context.Person.Where(p => p.Surname.Contains("Ai"));
tmp = WhereFemale(tmp);
var res = tmp.ToList();

Another approach - you can create extension method:

public static IQueryable<Person> WhereFemale(this IQueryable<Person> query)
{
    return query.Where(p => p.IsFemale);
}

and now you can use method chaining:

var res = _context.Person
    .Where(p => p.Surname.Contains("Ai"))
    .WhereFemale(tmp)
    .ToList();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文