升级到. net 7后LINQ表达式错误



从。net 2.2升级到。net 7后,以下LINQ表达式失败,并出现"LINQ表达式无法被翻译"错误。要么用可翻译的形式重写查询,要么显式地切换到客户端评估":

string excludeString = "XX";
string excludeString2 = "XX";
var groupfilter = await _db.UserGroup.Where(q => q.UserName == currUserName && q.IsActive == false && q.WorkGroupName == "BB").ToListAsync();
if (groupfilter.Any())
excludeString = "BB";
groupfilter = await _db.UserGroup.Where(q => q.UserName == currUserName && q.IsActive == false && q.WorkGroupName == "TS").ToListAsync();
if (groupfilter.Any())
excludeString2 = "TS";
DriveListViewModel model = new DriveListViewModel()
{
Drive = await _db.Drive
.Where(m => m.StatusId == 5 || m.StatusId == 1010 || m.StatusId == 1012)
.Where(m => m.LoadingComplete == null)
.Where(m => !m.UnitCode.Contains(excludeString))
.Where(m => !m.UnitCode.Contains(excludeString2))
.Include(s => s.DriveStatus)
.Include(d => d.Location)
.Include(f => f.Item)
.GroupBy(m => m.RegistrationNumber)
.Select(m => m.FirstOrDefault())
.OrderBy(m => m.DriverToLoad)
.ToListAsync(),
machineryList = await _db.Machinery.ToListAsync(),
cleaningList = await _db.Cleaning.ToListAsync(),
};

禁用这3行删除错误:

.GroupBy(m => m.RegistrationNumber)
.Select(m => m.FirstOrDefault())
.OrderBy(m => m.DriverToLoad)

…但是,我需要这个列表在"registrationnumber"上是不同的,所以我需要修改查询来获得相同的结果。

如何在。net 7中解决这个问题?

EF Core 2.2查询从一开始就不工作。EF Core没有发出警告,而是默默地将所有匹配的行加载到内存中,并在客户端对它们进行分区。EF Core 2非常有限,许多重要的操作(如GroupBy)无法转换为SQL,因此使用了静默客户端评估。我怀疑应用程序已经记录了关于此的EF警告。

EF Core 3.0增加了对所有重要操作的支持,因此默认情况下禁用了客户端评估。当您只希望按10个类别加载SUM时,加载10000行并不是一种很好的体验。从EF Core 3开始,不能转换为SQL的表达式会抛出异常。

最初的查询也没有做它看起来要做的事情,并且产生一些随机的结果。表或查询结果中没有隐式顺序,除非使用了ORDER BY子句。在.Select(m => m.FirstOrDefault())中没有这样的子句,所以从数据库返回的第一个对象被使用,无论它是什么。

如果目的是为每个RegistrationNumber返回DriverToLoad的第一个Driver,则以下查询应该可以工作:

var statuses=new[]{5,1010,1012};
var drives=await _db.Drive
...
.GroupBy(m => m.RegistrationNumber)
.Select(g => g.OrderBy(m=>m.DriverToLoad).Take(1))
.ToListAsync()

Where子句也可以简化很多,并且包含一些性能问题。

这个条件转换为LIKE '%%XX%%,它不能使用任何索引,并可能导致全表扫描:

.Where(m => !m.UnitCode.Contains(excludeString))

另一方面,前缀搜索可以使用索引,因为它本质上是前缀和下一个最大字符串之间的范围搜索。如果可能,使用

.Where(m => !m.UnitCode.StartsWith(excludeString))

最新更新