我们可以在 LINQ to SQL 中使用 ToLowerInvariant() 吗?

发布于 2025-01-18 09:38:59 字数 628 浏览 0 评论 0原文

我有一种使用DBContext和EF Core检索餐厅表结果的方法:

    public IEnumerable<Restaurant> GetRestaurantByName(string? name = null)
    {
        if (string.IsNullOrEmpty(name))
        {
            return _dbContext.Restaurants;
        }
        else
        {
            return _dbContext.Restaurants
                .Where(r => r.Name.ToLower().Contains(name.ToLowerInvariant()));
        }
    }

问题是当我尝试使用r.name.tolowerinvariant()而不是r.name时,问题是。 tolower()我捕获了一个例外,其中包含以下详细信息:

无效的exception:linq表达式'dbset() 。

我喜欢理解场景背后的确切原因和逻辑。

I have a method to retrieve Restaurant table results using DbContext and EF Core with the following code:

    public IEnumerable<Restaurant> GetRestaurantByName(string? name = null)
    {
        if (string.IsNullOrEmpty(name))
        {
            return _dbContext.Restaurants;
        }
        else
        {
            return _dbContext.Restaurants
                .Where(r => r.Name.ToLower().Contains(name.ToLowerInvariant()));
        }
    }

The problem is when I try to use r.Name.ToLowerInvariant() instead of r.Name.ToLower() I catch an exception with the following detail:

InvalidOperationException: The LINQ expression 'DbSet()
.Where(r => r.Name.ToLowerInvariant().Contains(__ToLowerInvariant_0))' could not be translated.

I like to understand the exact reason and logic behind the scene.

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

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

发布评论

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

评论(2

黎歌 2025-01-25 09:38:59

我喜欢理解场景背后的确切原因和逻辑。

您需要欣赏EFC是翻译人员。它查看您已构建的LINQ查询,并将其逐个转换为SQL,然后

在说:

context.Persons.Where(p => p.Name == "SMITH")

它变成:

SELECT * FROM persons WHERE name = 'SMITH'

当您说:

context.Persons.Where(p => p.Name.ToLower() == "SMITH")

它变为:

SELECT * FROM persons WHERE LOWER(name) = 'SMITH'

这两个可能的功能相同时,它将运行SQL; C#是案例敏感的,但SQL Server可能不是(默认情况下它使用不敏感的整理),因此,即使C#看起来像是胡说八道:

Name.ToLower() == "SMITH" //this would never return anything in C#

SQLServer处于不敏感的模式下会运行它并返回结果:

LOWER(name) = 'SMITH' --SQLServer will return

您必须保持意识到事实。您的c#被翻译成另一种语言,并根据该语言的规则运行,而不是C#

如果您想查看查询的内容,请不要运行它:

var q = context.Persons.Where(p => p.Name.ToLower() == "SMITH")
  //.ToList() //don't run it

现在指向q在调试器中检查debugview- efc将告诉您它生成的SQL(EFC5+功能)


现在记住,我们说这是翻译练习-EFC只能翻译

如果您使LINQ太复杂,您也会遇到错误;您必须找到另一种编写可以翻译的LINQ,或将命中率调整并下载到C#并在此处处理的LINQ

I like to understand the exact reason and logic behind the scene.

You need to appreciate that EFC is a translator. It looks at the LINQ query you have built and translates it piece by piece into SQL, then it runs the SQL

When you say:

context.Persons.Where(p => p.Name == "SMITH")

It becomes:

SELECT * FROM persons WHERE name = 'SMITH'

When you say:

context.Persons.Where(p => p.Name.ToLower() == "SMITH")

It becomes:

SELECT * FROM persons WHERE LOWER(name) = 'SMITH'

These two probably function the same anyway; C# is case sensitive but SQL Server probably isn't (by default it uses insensitive collation) so even though the C# looks like nonsense:

Name.ToLower() == "SMITH" //this would never return anything in C#

SQLServer in insensitive mode will run it and return results:

LOWER(name) = 'SMITH' --SQLServer will return

You have to remain conscious of the fact that your C# is translated into another language and run according to the rules of that language, not C#

If you want to see what your query becomes, don't run it:

var q = context.Persons.Where(p => p.Name.ToLower() == "SMITH")
  //.ToList() //don't run it

Now point to q in the debugger and inspect the DebugView- EFC will tell you what SQL it generates (EFC5+ feature)


Now remember we said it's a translation exercise - EFC can only translate what it knows - that's for sql server, different providers translate differently. If you use a function that it doesn't know, like ToLowerInvariant, you get an error. No one at Microsoft(or whoever wrote the provider you're using) has ever sat down and worked out a way to convert ToLowerInvariant into SQL in a meaningful way.

If you make your LINQ too complex you also get an error; you have to find another way to write the LINQ that can be translated, or take the hit and download a (?huge) amount of data into C# and process it there

靑春怀旧 2025-01-25 09:38:59

这是我一直困扰且难以调试的问题。在使用 DB 内的函数时,where 函数在某种程度上受到限制。

这是一个示例:

DataContext.Products.Where(product => product.Count > 5); \\ This works fine
DataContext.Products.Where(product => product.Name == "Mac".ToLower()); \\ Also works fine because "Mac" will be converted into "mac" before being inserted in the query, so it's value is handled in the app, not db server, and will be in the query as a static value.
\\ Now here let's make a call on the product
DataContext.Products.Where(product => product.Name.ToLowerInvariant() == "mac"); \\ Throws an exception because function ToLowerInvariantis not registered in the DB, so the DB doesn't know how to call this function or handle it.

如果您尝试调用这些针对 DB 的 where 语句内的函数,也会发生同样的事情

public bool HasItems(Product prod) => prod.Count > 0;
DataContext.Products.Where(prod => HasItems(Prod)); // Also throws the same exception cause the function is again is not mapped to any DB Function.

如果您尝试将 HasItems 设为仅 Getter 属性会怎样?

public class Product {
    public int Count {get;set;}
    public bool HasItems => Count > 0;
}

DataContext.Products.Where(prod => prod.HasItems); 
// Will throw an exception, cause migration won't register HasItems as computed column, so this property is not known in the DB and it doesn't know how to get its value.

因此,只要您尝试调用的函数或列未在数据库服务器中注册,并且查询将在数据库服务器内部运行,就会抛出异常。但是,如果您对应用程序中可用的数据使用相同的查询,它们就会正常工作。

This is a problem that I always suffer from and hard to debug. The where function is somehow limited when it comes to using Functions inside DB.

Here is an example:

DataContext.Products.Where(product => product.Count > 5); \\ This works fine
DataContext.Products.Where(product => product.Name == "Mac".ToLower()); \\ Also works fine because "Mac" will be converted into "mac" before being inserted in the query, so it's value is handled in the app, not db server, and will be in the query as a static value.
\\ Now here let's make a call on the product
DataContext.Products.Where(product => product.Name.ToLowerInvariant() == "mac"); \\ Throws an exception because function ToLowerInvariantis not registered in the DB, so the DB doesn't know how to call this function or handle it.

and the same thing happens if you try to call functions inside these where statements that work against DB

public bool HasItems(Product prod) => prod.Count > 0;
DataContext.Products.Where(prod => HasItems(Prod)); // Also throws the same exception cause the function is again is not mapped to any DB Function.

What if you try to make HasItems as Getter Property Only?

public class Product {
    public int Count {get;set;}
    public bool HasItems => Count > 0;
}

DataContext.Products.Where(prod => prod.HasItems); 
// Will throw an exception, cause migration won't register HasItems as computed column, so this property is not known in the DB and it doesn't know how to get its value.

So as long as functions or columns you try to call are not registered in the DB Server, and the query will work inside the DB Server, it will throw an exception. But if you use the same queries with data that are available in the app, they will work just fine.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文