我试图从数据库中检索产品列表,其中名称包含,开始或结束于我作为参数传递给执行查询的方法的任何列表元素。
我已经尝试了Linq方法(方法和查询语法)
以下是Linq方法查询的相关代码,名称是作为方法参数传递的名称列表:
var query = _dbContext.Products
.Where(p => p.IdExternalProduct == null &&
names.Any(name => p.ProductName.Contains(name)))
.Select(item => new ProductEntity() { Uuid = item.Uuid, Code = item.Code});
或
var query = _dbContext.Products
.Where(p => p.IdExternalProduct == null &&
names.Any(name => p.ProductName.StartsWith(name)))
.Select(item => new ProductEntity() { Uuid = item.Uuid, Code = item.Code});
下面是查询语法方法:
IQueryable<ProductEntity> query = (
from p in _dbContext.Products
where
p.IdExternalProduct == null &&
(names != null && names.Count > 0 ? names.Any(name => p.ProductName.Contains(name)) : true)
select new ProductEntity()
{
Uuid = p.Uuid,
Code = p.Code
}
当我尝试使用Equals
而不是Contains
,StartsWith
或EndsWith
时,完全相同的查询工作。
我搜索了很多,找到了很多资源,但没有解决方案适合我。
这里有两个相关的Stack overflow问题,Jon Skeet建议使用相同的实现。
使用Linq
检查列表中的字符串是否包含特定的字符串正确的LINQ where子句
我正在使用6.0.10版本的实体框架和SQL Server提供程序。
但是这些公式似乎不能被翻译,抛出了一个异常,消息如下:
LINQ表达式的name =>EntityShaperExpression:
Service.Product。Products
ValueBufferExpression:
ProjectionBindingExpression: EmptyProjectionMember
IsNullable: False
. productname . contains (name)'无法翻译。要么以可翻译的形式重写查询,要么通过插入对'AsEnumerable', 'AsAsyncEnumerable', 'ToList'或'ToListAsync'的调用显式切换到客户端计算。详见https://go.microsoft.com/fwlink/?linkid=2101038
Jon Skeet在其他SO答案中推荐此实现的原因是因为它引用IEnumerable
查询(linq-to-object)而不是IQueryable
查询(linq-to-entities)。Linq-to-object在内存对象上执行,并且实际上将执行string.Contains
方法。给EF的方法实际上并没有执行,它们被翻译成SQL语句,efcore 6不知道如何翻译你的语句,特别是name
变量,它来自IEnumerable.Any
调用中的linq到object lambda。
大多数开发人员忘记了IQueryable<T>
是一个累积类型,您可以在其上聚合谓词。一个简单的解决方案是对每个名称进行联合查询,并区分所有结果:
var query = names.Select(name => _dbContext.Products
.Where(product => product.IdExternalProduct == null)
.Where(product => product.ProductName.Contains(name)))
.Aggregate(Queryable.Union)
.Distinct()
.Select(product => new ProductEntity(...));
这个查询产生以下语句:
DECLARE @__name_0 nvarchar(4000) = N'a';
DECLARE @__name_1 nvarchar(4000) = N'b';
SELECT DISTINCT [t].[Id], [t].[IdExternalProduct], [t].[ProductName]
FROM (
SELECT [p].[Id], [p].[IdExternalProduct], [p].[ProductName]
FROM [Products] AS [p]
WHERE ([p].[IdExternalProduct] IS NULL) AND ((@__name_0 LIKE N'') OR CHARINDEX(@__name_0, [p].[ProductName]) > 0)
UNION
SELECT [p0].[Id], [p0].[IdExternalProduct], [p0].[ProductName]
FROM [Products] AS [p0]
WHERE ([p0].[IdExternalProduct] IS NULL) AND ((@__name_1 LIKE N'') OR CHARINDEX(@__name_1, [p0].[ProductName]) > 0)
) AS [t]