EntityFramework:SQL上的Linq:包含还是IndexOf?

问题描述 投票:1回答:1

我对使用.NET 4.5(C#)的EntityFramework 6感到很奇怪。

我在两个不同的地方有(几乎)相同的查询。但是,它再次查询数据库,第二次查询内存中的对象。由于我要过滤一个子字符串,所以这是一个关键的区别:

数据库结构是表角色,权限和交叉表角色_权限

第一次,我想找到尚未分配给角色的所有可用权限,加上(这使情况变得复杂)手动过滤器以减少结果列表:

Role role = ...;
string filter = ...;
var roleRightNames = role.Right.Select(roleRight => roleRight.RightName);
var filteredRights = context.Right.Where(right => !roleRightNames.Contains(right.RightName));
if (!string.IsNullOrWhiteSpace(filter))
{
    filteredRights = filteredRights.Where(e => e.RightName.Contains(filter));
}
var result = filteredRights.ToList();

我无法使用IndexOf(filter, StringComparison.InvariantCultureIgnoreCase) >= 0),因为无法将其转换为SQL。但我对Contains表示满意,因为它可以产生所需的结果(请参见下文)。

启用SQL输出时,我得到:

SELECT [Extent1].[RightName] AS [RightName]
FROM [dbo].[Right] AS [Extent1]
WHERE ( NOT ([Extent1].[RightName] IN ('Right_A1', 'Right_A2', 'Right_B1'))) AND ([Extent1].[RightName] LIKE @p__linq__0 ESCAPE '~')
-- p__linq__0: '_a' (Type = AnsiString, Size = 8000)

正是我想要的,对过滤器“ _a”不区分大小写的搜索,例如“ Right_A3”

第二次我想为同一过滤器过滤现有的关联权限:

Role role = ...;
string filter = ...;
var filteredRights = string.IsNullOrWhiteSpace(filter)
    ? role.Right
    : role.Right.Where(e => e.RightName.IndexOf(filter, StringComparison.InvariantCultureIgnoreCase) >= 0);            
var result = filteredRights.ToList();

这一次迫使我使用IndexOf,因为它使用了Containsstring方法而不是将其转换为SQL LIKE并且string.Contains区分大小写。

[我的问题是,我无法通过查看代码来预测何时对数据库执行查询以及何时在内存中完成查询,并且由于我无法在第一个查询中使用IndexOf而在数据库中无法使用Contains第二,这对我来说似乎有点不可预测。有一天第一天执行第二个查询并且数据还没有在内存中时,会发生什么?

c# entity-framework linq-to-sql entity-framework-6
1个回答
0
投票

我的问题是,我无法-通过查看代码-预测何时针对数据库以及在内存中执行查询时并且由于我无法在第一个查询中使用IndexOf以及在第二,这对我来说似乎有点不可预测。

只要您不使用带有IndexOf的重载,就可以在两个查询中都使用ContainsStringComparison。如@BrettCaswell所指出的,大小写匹配由数据库/表/列的排序规则固定。如果查询的根是上下文的DbSet,并且所有方法调用都可以转换为SQL,则该查询将转换为SQL。

一旦方法无法翻译,当前状态请求将在SQL级别执行,而查询的其余部分将在.Net应用程序的内存中执行。

此外,我认为p__linq__0值应为'%~_a%',因为_LIKE子句中的特殊字符。

© www.soinside.com 2019 - 2024. All rights reserved.