如何使用 Any(x => DbFunctions.Like()) 优化 LINQ Where 条件
How to optimize a LINQ Where condition with Any(x => DbFunctions.Like())
此 LINQ 语句:
var entities = SomeEntities.Where(se => se.SomeProperty == "SomeValue");
var stringList = new List<string> { "string1", "string2", "string3" }
var startsWith = stringList.Select(x => x + "%");
entities = entities.Where(e => startsWith.Any(sw => DbFunctions.Like(e.StringProperty, sw))).Select(e => e.Id);
类似的 SQL 查询结果如下:
SELECT
[Project8].[Id] AS [Id]
FROM ( SELECT
[Extent1].[Id] AS [Id],
FROM [SomeEntities] AS [Extent1]
WHERE ([Extent1].[SomeProperty] == 'SomeValue') AND( EXISTS (SELECT
1 AS [C1]
FROM (SELECT
N'string1%' AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
UNION ALL
SELECT
N'string2%' AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable2]
UNION ALL
SELECT
N'string3%' AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable3]) AS [UnionAll2]
WHERE [Extent1].[StringProperty] LIKE [UnionAll2].[C1]
)))
) AS [Project8]
ORDER BY [Project8].[Status] DESC
如何实现类似于以下的查询:
SELECT [Id]
FROM [SomeEntities]
WHERE [SomeProperty] == 'SomeValue'
AND (StringProperty] LIKE 'string1%'
OR StringProperty] LIKE 'string2%'
OR StringProperty] LIKE 'string3%')
entities = entities.Where(e => startsWith.Any(sw => e.StringProperty.Contains("string1") || e.StringProperty.Contains("string2") || e.StringProperty.Contains("string3") ))).Select(e => e.Id);
你可以试试:
var entityIds = SomeEntities
.Where(se => se.SomeProperty == "SomeValue"
&& stringList.Any(sw => se.StringProperty.StartsWith(sw)))
.Select(se=>se.Id);
首先,我建议使用 PredicateBuilder 进行复杂查询。它有助于轻松创建和组合表达式,然后使用 EF 对其求值。
然后, EF.Functions.Like
和 Contains, StartWith, etc
决定你需要哪一个。
代码示例:
List<string> searchStrings=new List<string>(){"name1","name2","name3"};
var predicate = searchStrings
.Select<string, Expression<Func<Person, bool>>>(search => item => EF.Functions.Like(item.Name, $"{search}%"))
.DefaultIfEmpty(patient => false) //or whatever else you want to do if there are no search strings
.Aggregate(PredicateBuilder.Or);
predicate = predicate.And(item => item.Deleted == null);
var filteredPatients = await _context.Persons.Where(predicate).ToListAsync();
来自 sql 服务器分析器的查询:
exec sp_executesql N'SELECT [p].[Id], [p].[B], [p].[Deleted], [p].[Email],
[p].[Name] FROM [Persons] AS [p]
WHERE [p].[Deleted] IS NULL AND (((([p].[Name] LIKE @__Format_1) OR ([p].
[Name] LIKE @__Format_2)) OR ([p].[Name] LIKE @__Format_3)) AND [p].[Deleted]
IS NULL)',N'@__Format_1 nvarchar(4000),@__Format_2 nvarchar(4000),@__Format_3
nvarchar(4000)',@__Format_1=N'name1%',@__Format_2=N'name2%',@__Format_3=N'name3%'
此 LINQ 语句:
var entities = SomeEntities.Where(se => se.SomeProperty == "SomeValue");
var stringList = new List<string> { "string1", "string2", "string3" }
var startsWith = stringList.Select(x => x + "%");
entities = entities.Where(e => startsWith.Any(sw => DbFunctions.Like(e.StringProperty, sw))).Select(e => e.Id);
类似的 SQL 查询结果如下:
SELECT
[Project8].[Id] AS [Id]
FROM ( SELECT
[Extent1].[Id] AS [Id],
FROM [SomeEntities] AS [Extent1]
WHERE ([Extent1].[SomeProperty] == 'SomeValue') AND( EXISTS (SELECT
1 AS [C1]
FROM (SELECT
N'string1%' AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
UNION ALL
SELECT
N'string2%' AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable2]
UNION ALL
SELECT
N'string3%' AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable3]) AS [UnionAll2]
WHERE [Extent1].[StringProperty] LIKE [UnionAll2].[C1]
)))
) AS [Project8]
ORDER BY [Project8].[Status] DESC
如何实现类似于以下的查询:
SELECT [Id]
FROM [SomeEntities]
WHERE [SomeProperty] == 'SomeValue'
AND (StringProperty] LIKE 'string1%'
OR StringProperty] LIKE 'string2%'
OR StringProperty] LIKE 'string3%')
entities = entities.Where(e => startsWith.Any(sw => e.StringProperty.Contains("string1") || e.StringProperty.Contains("string2") || e.StringProperty.Contains("string3") ))).Select(e => e.Id);
你可以试试:
var entityIds = SomeEntities
.Where(se => se.SomeProperty == "SomeValue"
&& stringList.Any(sw => se.StringProperty.StartsWith(sw)))
.Select(se=>se.Id);
首先,我建议使用 PredicateBuilder 进行复杂查询。它有助于轻松创建和组合表达式,然后使用 EF 对其求值。
然后,EF.Functions.Like
和 Contains, StartWith, etc
决定你需要哪一个。
代码示例:
List<string> searchStrings=new List<string>(){"name1","name2","name3"};
var predicate = searchStrings
.Select<string, Expression<Func<Person, bool>>>(search => item => EF.Functions.Like(item.Name, $"{search}%"))
.DefaultIfEmpty(patient => false) //or whatever else you want to do if there are no search strings
.Aggregate(PredicateBuilder.Or);
predicate = predicate.And(item => item.Deleted == null);
var filteredPatients = await _context.Persons.Where(predicate).ToListAsync();
来自 sql 服务器分析器的查询:
exec sp_executesql N'SELECT [p].[Id], [p].[B], [p].[Deleted], [p].[Email],
[p].[Name] FROM [Persons] AS [p]
WHERE [p].[Deleted] IS NULL AND (((([p].[Name] LIKE @__Format_1) OR ([p].
[Name] LIKE @__Format_2)) OR ([p].[Name] LIKE @__Format_3)) AND [p].[Deleted]
IS NULL)',N'@__Format_1 nvarchar(4000),@__Format_2 nvarchar(4000),@__Format_3
nvarchar(4000)',@__Format_1=N'name1%',@__Format_2=N'name2%',@__Format_3=N'name3%'