简体   繁体   English

如何在Linq中使用Where运算符

[英]How to use Where operator in Linq

SomeObject.Where(p => FunctionOn(p.I));
<<>>
public bool FunctionOn(int i){
    return (i == 1);}
<<>>
error message : The method FunctionOn is not supported 

but why when I use number instead of parameter it works fine ? 但为什么当我使用数字而不是参数时它工作得很好?

SomeObject.Where(p => FunctionOn(1));

I was wondering if there is a way to implement this code in Linq , because it gives me an error . 我想知道是否有办法在Linq中实现此代码,因为它给了我一个错误。
Thank you . 谢谢 。

您需要更具体地了解实际获得的错误,但是,作为一般指南,如果FunctionOn无法转换为数据库特定语言查询(如果SomeObject是数据库实体)或者它不返回布尔值,则通常会失败Where函数期望的值。

 SomeObject.Where(p => FunctionOn(pI)); 

You said that SomeObject is an IQueryable . 你说SomeObject是一个IQueryable This makes me suspect that you aren't querying an in-memory collection (LINQ-to-Objects), where your query should succeed without any problems, but you're possibly querying something more "dynamic". 这让我怀疑你没有查询内存中的集合(LINQ-to-Objects),你的查询应该没有任何问题地成功,但你可能会查询更“动态”的东西。 For the sake of demonstrating the problem, I will assume that we're dealing with LINQ-to-SQL here... but that assumption doesn't have to be necessarily true for what I would like to explain below: 为了演示这个问题,我假设我们在这里处理LINQ-to-SQL ......但是这个假设并不一定适用于我想在下面解释的内容:

Update: You've just said in a comment that you're using LINQ-to-MongoDB, so the below should apply to your issue. 更新:您刚刚在评论中说您正在使用LINQ-to-MongoDB,因此以下内容应适用于您的问题。

With something like LINQ-to-SQL, the problem with your query isn't that something's wrong with the FunctionOn predicate method, or with the way you're combining it with the Where operator. 对于像LINQ-to-SQL这样的东西,查询的问题不是FunctionOn谓词方法的错误,或者是你将它与Where运算符组合的方式。 The problem at hand is that LINQ-to-SQL (or whatever LINQ provider you're using) doesn't recognise your method. 手头的问题是LINQ-to-SQL(或者你正在使用的任何LINQ提供程序)无法识别你的方法。 It's trying to convert your LINQ expression into an SQL query at runtime (that's exactly what IQueryable is good for, after all!), but it doesn't know how to convert your FunctionOn to SQL. 它试图在运行时将LINQ表达式转换为SQL查询(毕竟这正是IQueryable的好处!),但它不知道如何将FunctionOn转换为SQL。

If LINQ-to-SQL were to achieve this, it would have to figure out what your method is doing, and then find a way to express that as valid SQL. 如果LINQ-to-SQL要实现这一点,就必须弄清楚你的方法在做什么,然后找到一种方法来表达它作为有效的SQL。 That would take a lot of sophistication and intelligence. 这将需要很多复杂性和智慧。 For example, it would have to inspect your method eg by decompiling it, and then re-compiling it as SQL. 例如,它必须检查您的方法,例如通过反编译,然后将其重新编译为SQL。 This clearly cannot work for any arbitrarily complex method. 这显然不适用于任何任意复杂的方法。 Imagine that your FunctionOn method contained a call to Debug.WriteLine . 想象一下,你的FunctionOn方法包含对Debug.WriteLine的调用。 There's no way that this could be translated into an SQL query. 这无法将其转换为SQL查询。

Thus LINQ-to-SQL is restricted to a few cases and expressions that it knows how to handle. 因此,LINQ-to-SQL仅限于一些知道如何处理的情况和表达式。 If it encounters anything else in a LINQ expression, it'll let you know that it doesn't know how to handle FunctionOn (ie. how to convert it to SQL) by saying something like, "The method FunctionOn is not supported." 如果它在LINQ表达式中遇到任何其他内容,它会让你知道它不知道如何处理FunctionOn (即如何将它转换为SQL),可以说“不支持FunctionOn方法”。

Once you write your query as: 将查询编写为:

SomeObject.Where(p => p.I == 1);

everything should work fine, since LINQ-to-SQL knows how to translate your pI == 1 to a corresponding equality test in a SQL WHERE clause. 一切都应该工作正常,因为LINQ-to-SQL知道如何将pI == 1转换为SQL WHERE子句中的相应的相等测试。

This might work, Try : 这可能有效,请尝试:

SomeObject.AsEnumerable().Where(p => FunctionOn(p.I))

It would work for Linq-To-Entities and Linq-To-SQL too! 它也适用于Linq-To-Entities和Linq-To-SQL!

Why! 为什么! How? 怎么样?

Because like stakx explains. 因为像stakx解释的那样。 IQueryable stores your expression. IQueryable存储你的表达。 If you check out the docs for IQueryable it has an Expression property, this stores the Linq you write in your code, and then a LinqProvider then translates it into the right thing, in your case that would be MongoDB syntax/SQL IDK? 如果您查看了IQueryable文档,它有一个Expression属性,这会将您在代码中编写的Linq 存储起来 ,然后LinqProvider会将其转换为正确的东西,在您的情况下是MongoDB语法/ SQL IDK? For linq-to-sql this would turn into an T-SQL expression. 对于linq-to-sql,这将转变为T-SQL表达式。 So there is no SQL-way to write FunctionOn() . 所以没有SQL方法来编写FunctionOn() Can it magically call your function written in C# from SQL? 可以用SQL神奇地调用用C#编写的函数吗? Nope! 不!

Now, IEnumerable is an object collection in memory. 现在, IEnumerable是内存中的对象集合。 When you say AsEnumerable() you get the objects in memory , then when you do Where(x=> func(x)) Linq-To-Objects can handle it no problem. 当你说AsEnumerable()你得到内存中的对象 ,然后当你做Where(x=> func(x)) Linq-To-Objects可以处理它没问题。

Like @Will on the comments rightly says, this gets every single object into memory and then queries it. 就像@Will对评论的正确说法一样,这会将每个对象都放入内存然后查询它。 At times it may not be what you want to do, but I wanted you to understand why your code doesn't work and also if you needed there is sorta a workaround 有时它可能不是你想要做的,但我希望你理解为什么你的代码不起作用,如果你需要,还有一种解决方法

Hope it gave you the same insight I discovered a few weeks ago while watching lots of channel9 Linq Videos. 希望它能给你几周前在观看很多9频道Linq视频时发现的相同见解。 =) =)

As others have mentioned, your FunctionOn method isn't directly translatable by your data source. 正如其他人所提到的,您的FunctionOn方法不能直接由您的数据源进行翻译。

However, there may be a way around it - depending upon what sort of comparison you need to do, and how big of a comparison you're making. 但是,可能有一种解决方法 - 取决于您需要做什么样的比较,以及您正在进行的比较有多大。

If instead, you create an extension method which takes an IQueryable<T> and returns IQueryable<T> you can write your expression directly. 相反,如果您创建了一个扩展方法,它接受IQueryable<T>并返回IQueryable<T>您可以直接编写表达式。

This allows you to re-use complex expressions. 这允许您重用复杂的表达式。 You should also be able to compare against a list of reference data - however you'll need to take care that this comparison list doesn't exceed the parameters permitted for your datasource. 您还应该能够与参考数据列表进行比较 - 但是您需要注意此比较列表不会超出数据源允许的参数。

Example: 例:

static void Main(string[] args)
{


    var data = new List<Customer>
                {
                    new Customer {Id = 1, Name = "Anna"},
                    new Customer {Id = 2, Name = "Bob"},
                    new Customer {Id = 3, Name = "Claire"}
                };



    var result = data.AsQueryable().TestCustomer();




}

private static IQueryable<Customer> TestCustomer(this IQueryable<Customer> source)
{
    return source.Where(x => x.Id > 1);
}


public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
}

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

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