【发布时间】:2020-07-17 17:47:43
【问题描述】:
我有这样的查询
public IEnumerable<ContractInquiry> ContractInquiry(Guid itemSoldID)
{
IEnumerable<ContractInquiry> result;
using (var context = new ContractDbContext(_ctxOptions))
{
var qry = from con in context.Contracts
join product in context.ContractProducts on con.ID equals product.ContractID
join service in context.ServiceDetails on con.ID equals service.ContractID into tmpService
from service in tmpService.DefaultIfEmpty()
where product.ItemSoldID == itemSoldID
&& product.ProductStatus != ProductStatus.Deleted.ToString()
&& con.Status != Status.Deleted.ToString()
select new ContractInquiry
{
ServiceID = con.ID,
ServiceType = con.ServiceType,
ServiceDate = service.ServiceDate,
ServiceNumber = service.ServiceNumber,
ServiceManager = con.Contacts.Where(q => q.Role.Contains(ContractRole.ServiceManager.ToString()))
.OrderBy(o => o.ID).FirstOrDefault()
};
result = qry.ToList();
}
return result;
}
此查询运行良好。但是当我们升级到 .NET Core 3.1.5 和 Entity Framework Core 3.1.5 时,它开始抛出客户端评估错误:
“无法翻译。要么以可翻译的形式重写查询,要么通过插入对 AsEnumerable()、AsAsyncEnumerable()、ToList() 或 ToListAsync() 的调用显式切换到客户端评估。 "
所以我不得不从查询中取出以下行:
ServiceManager = con.Contacts.Where(q => q.Role.Contains(ContractRole.ServiceManager.ToString()))
.OrderBy(o => o.ID).FirstOrDefault()
所以重新编写了这样的查询:
public IEnumerable<ContractInquiry> ContractInquiry(Guid itemSoldID)
{
List<ContractInquiry> result;
using (var context = new ContractDbContext(_ctxOptions))
{
var result = (from con in context.Contracts
join product in context.ContractProducts on con.ID equals product.ContractID
join service in context.ServiceDetails on con.ID equals service.ContractID into tmpService
from service in tmpService.DefaultIfEmpty()
where product.ItemSoldID == itemSoldID
&& product.ProductStatus != ProductStatus.Deleted.ToString()
&& con.Status != Status.Deleted.ToString()
select new ContractInquiry
{
ServiceID = con.ID,
ServiceType = con.ServiceType,
ServiceDate = service.ServiceDate,
ServiceNumber = service.ServiceNumber,
Contacts = con.Contacts
}).ToList();
}
result.ForEach(con => con.Contacts.Where(q => q.Role.Contains(ContractRole.ServiceManager.ToString()))
.OrderBy(o => o.ID).FirstOrDefault();
return result;
}
这里
con.Contacts
是Contract.cs类中的一个表格集合
我在 ContractInquiry.cs 类中添加了这样的属性:
[JsonIgnore]
public IEnumerable<Contact> Contacts { set; get; }
这也很好。
问题: 这样做可以正常工作,但在运行时,表集合“con.Contacts”将在内存中,对吗?如果表是一个巨大的集合,那会影响查询的性能吗?那么有没有办法解决这个问题而不是使用内存表?如何在我的第一个查询中从 select 子句中取出“ServiceManager = ..”?
更新:有人可以回答我的问题吗?
【问题讨论】:
-
与其从查询中取出,不如找出表达式的哪个部分导致了问题。 EFC 最有可能显示整个表达式,但问题出在其中一个部分(
Where、OrderBy等)。所以开始一一删除它们(我会从Where子句开始)直到它起作用。 -
我检查了一下,发现问题出在 select 子句 "ServiceManager = con.Contacts.Where(q => ........" 中的以下行。如果我评论这条线它有效。我希望问题出在 .Contains() 上。这就是为什么我需要取消客户端评估。
-
你需要专注于那个表达而不是整体。例如,从显示的代码中不清楚什么是
ContractRole- 类变量?静态成员?还有ContractRole.ServiceManager属性的类型和.ToString()调用的需要。在这种情况下我会尝试的第一件事是将该部分移动到查询之外的变量,例如var contractRoleServiceManager = ContractRole.ServiceManager.ToString();然后在里面使用q.Role.Contains(contractRoleServiceManager)。 -
ContractRole 是一个枚举。我可以试试你的建议。但我的问题是:有没有办法将“con.Contacts”集合带到外面单独评估?
-
有人能回答我的问题吗?
标签: c# .net-core-3.1 entity-framework-core-3.1