【问题标题】:SQL convert perfomance optimization in EF CoreEF Core 中的 SQL 转换性能优化
【发布时间】:2021-09-06 10:34:42
【问题描述】:

我正在尝试优化由 EF Core 生成的 SQL 查询。我正在使用 System.Linq.Dynamic.Core 和 Z.EntityFramework.Plus 来构造查询过滤器。我需要从我的列表中找到具有 ID 的对象数组。

string arraystr = filter.Value.Replace("array[", "{").Replace("]", "}");
Filters.Add(_context.Filter<TEntity>(x => x.Where($"new[] {arraystr}.Contains({exactName}.ToString())")));

filter.Value 来自 UI,它是一串 ID,如下所示:

array["ef47913f-8960-46ad-f8ff-08d865b62242","1617bed9-4369-44eb-b605-08d895a537c9", ...]

"Filters" - 是 BaseQueryFilter 的列表。

exactName - 要过滤的列的名称。

在结果中 EF Core 生成这样的查询

SELECT [c].[FirstName], [c].[ID], [c].[LastName]
FROM [Employee] AS [c]
WHERE NOT ([c].[IsDeleted] = CAST(1 AS bit))
AND CONVERT(VARCHAR(36), [c].[ID]) IN
(N'ef47913f-8960-46ad-f8ff-08d865b62242', N'1617bed9-4369-44eb-b605-08d895a537c9', N'ebd998be-9262-40aa-b604-08d895a537c9', N'6f472069-bd82-4686-7381-08d89800b4ae', N'a688c8bd-c045-42bd-737f-08d89800b4ae', N'292bc19d-1d1b-49ce-7384-08d89800b4ae')

“NOT ([c].[IsDeleted] = CAST(1 AS bit))”由实体配置生成

builder.HasQueryFilter(entity => !entity.IsDeleted);

我尝试使用另一种变体,例如

List<Guid?> array = JsonConvert.DeserializeObject<List<Guid?>>(filter.Value.Replace("array", string.Empty));
Filters.Add(_context.Filter<TEntity>(x => x.Where($"@0.Contains({exactName})", array)));

但它抱怨“包含”方法。

如何从查询中删除此 CONVERT?

UPD1: 我尝试使用此变体

Guid[] arraystr = JsonConvert.DeserializeObject<Guid[]>(filter.Value.Replace("array", string.Empty));
Filters.Add(_context.Filter<TEntity>(x => x.Where($"@0.Contains(new Guid({exactName}))", arraystr)));

但它不起作用。也许谓词有问题...

【问题讨论】:

  • 请避免使用诸如“抱怨”和“不起作用”之类的模糊短语。改为显示异常消息。
  • 在第一个变体数组中没有“包含”方法。在第二个变体中,无法将字符串转换为 Guid,因为 exactName 具有“ID”值。

标签: c# .net entity-framework-core asp.net-core-3.1


【解决方案1】:

我建议您先将字符串解析为Guid,而不是尝试将Guid 列转换为字符串:

var guids = filter.Value
  .Replace("array[", "")
  .Replace("]", "")
  .Split(",")
  .Select(s => Guid.Parse(s))
  .ToArray();

Filters.Add(_context.Filter<TEntity>(x => guids.Contains(x.Id));

您还可以使用

改进其他过滤器
builder.HasQueryFilter(entity => entity.IsDeleted == false);

这应该会产生类似下面的东西

SELECT [c].[FirstName], [c].[ID], [c].[LastName]
FROM [Employee] AS [c]
WHERE [c].[IsDeleted] = CAST(0 AS bit)
AND [c].[ID] IN
  (N'ef47913f-8960-46ad-f8ff-08d865b62242', N'1617bed9-4369-44eb-b605-08d895a537c9', N'ebd998be-9262-40aa-b604-08d895a537c9', N'6f472069-bd82-4686-7381-08d89800b4ae', N'a688c8bd-c045-42bd-737f-08d89800b4ae', N'292bc19d-1d1b-49ce-7384-08d89800b4ae')

【讨论】:

  • 我尝试使用这个变体``` Guid[] arraystr = JsonConvert.DeserializeObject(filter.Value.Replace("array", string.Empty)); Filters.Add(_context.Filter(x => x.Where($"@0.Contains(new Guid({exactName}))", arraystr))); ``` 但它不起作用。可能在谓词中......
  • 这不是我说的,是吗?您希望x =&gt; arraystr.Contains(x.exactName) 不涉及字符串插值
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-24
  • 2020-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多