我将 EF Core 7 与 .NET 6 Blazor Server 应用程序一起使用,我不确定哪里出了问题。数据库表似乎没有按照标准约定正确设置,因此这可能就是我出错的原因。
注意 - 我更改了表名称和列,因此事情可能不明白我为什么要查找某些内容,但只需忽略它并查看结构即可。
我有这两个表,我首先用代码表示。
public class TableA
{
public long Id { get; set; }
public string Name { get; set; }
public string SubName {get; set;}
public ICollection<TableB> TableBs {get; set;}
}
public class TableB
{
public long Id { get; set; }
public string DisplayValue { get; set; }
public string SearchValue { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public long? AId { get; set; } // this if the foreign key for TableA, the convention of TableAId is not followed here.
public TableA TableA { get; set; }
}
基本上TableA可以有很多TableB
由于在 TableB 中,FK 并未按照 EF 的预期命名,因此我必须在流畅的验证类中执行此操作(我仅显示相关信息,因此并不完整)
//Fluent Configuration
builder.ToTable("TableA", "schemaName")
builder.HasMany(x => x.TableBs).WithOne(x => x.TableA).HasForeignKey(x => x.AId)
builder.ToTable("TableB", "schemaName")
builder.HasOne(x => x.TableA).WithMany(x => x.TableBs).HasForeignKey(x => x.AId)
现在我想搜索与 TableB 中的“SearchValue”匹配的任何值。
如果输入“Bob”,则应该找到以“Bob”开头的任何内容,例如“Bob Jim”、“Bob Frank”
在 SQL 中我会写这样的东西
SELECT p.DisplayValue, p.StartDate r.Name, r.SubName
FROM TableB as p INNER JOIN
TableA as r ON p.AId = r.Id
where p.SearchValue like 'Bob%' and p.EndDate is not null
我正在 SearchValue 上执行类似操作,并检查结束日期是否不为空。
然后我想返回 DisplayValue、开始日期、名称和子名称。
现在在 linq 我有
var results = context.TableB.Include(x => x.TableA).Where(x => x.SearchValue.Contains("Bob") && x.EndDate != null).Select(x = new {
DisplayValue = x.DisplayValue,
StartDate = x.StartDate,
Name = x.TableA.Name,
SubName = x.TableA.SubName
}).ToList();
这会产生这个sql语句
DECLARE @__SearchValue_0 nvarchar(20) = N'Bob';
SELECT [a].[Name], [a].[SubName], [p].[DisplayValue], [p].[StartDate]
FROM [schemaName].[TableB] as [p]
LEFT JOIN [schemaName].[TableA] AS [a] ON [p].[AId] = [a].[Id]
WHERE ((@__SearchValue_0 LIKE N'') or CHARINDEX(@__SearchValue_0, [p].[SearchValue]) > 0) AND ([p].EndDate IS NOT NULL)
现在我编写的 SQL 查询在不到一秒的时间内返回 10 个结果。 Linq 查询返回 14 个结果,需要 30 秒。
我认为结果差异是因为 contains 与 sql 中的“like”并不相同,我也尝试过 EF.Functions.Like,但它仍然很慢,但确实返回了相同的结果计数。
表 B 有 11,000 条记录,表 A 有 200 条记录。
首先我认为这是因为它决定执行 LEFT JOIN,所以我尝试使用 .JON() 编写查询并强制其进行 INNER JOIN,但它仍然需要 30 秒并返回 14 个结果。
所以我不确定我哪里错了。
如果我将其从 Contains() 更改为 == "Bob",那么查询似乎可以找到关于 EF core 如何构建它的信息,并且结果很快,但当然不正确。
首先,这些搜索不一样。但不确定这是否是整个问题。
Where(x => x.SearchValue.Contains("Bob"))
与
不一样p.SearchValue like 'Bob%'
更像是
p.SearchValue like '%Bob%'
所以也许可以使用类似的东西
Where(x => x.SearchValue.Substring(1, "Bob".Length) == "Bob")
可能会生成更好的 SQL
(我假设您在实际使用中会在此处使用变量)