Linq EF Core复杂查询将针对参数的每个变化进行缓存
我有一个复杂的查询,它似乎会导致我的应用程序内存出现内存泄漏 据我所知,查询结果是缓存的,因此不需要每次执行查询时都进行此处理 但它看起来是这样的:对于登录到系统中的每个用户,查询都会被缓存。从内存转储来看,似乎同一查询有数千个已编译查询缓存对象 查询如下所示Linq EF Core复杂查询将针对参数的每个变化进行缓存,linq,.net-core,entity-framework-core,ef-core-2.2,dotmemory,Linq,.net Core,Entity Framework Core,Ef Core 2.2,Dotmemory,我有一个复杂的查询,它似乎会导致我的应用程序内存出现内存泄漏 据我所知,查询结果是缓存的,因此不需要每次执行查询时都进行此处理 但它看起来是这样的:对于登录到系统中的每个用户,查询都会被缓存。从内存转储来看,似乎同一查询有数千个已编译查询缓存对象 查询如下所示 public async Task<IList<EmployeeInboxMessage>> GetEmployeeMessagesAsync(long employeeId) {
public async Task<IList<EmployeeInboxMessage>> GetEmployeeMessagesAsync(long employeeId)
{
return await (from message in this.Repository.Set
join userStep in this.Repository.Context.Set<UserWorkflowHeaderStep>() on message.UserWorkflowStepId equals userStep.UserWorkflowStepId into userSteps
from userStep in userSteps.DefaultIfEmpty()
join acceptedStep in this.Repository.Context.Set<CompanyWorkflowStep>() on userStep.AcceptedStepId equals acceptedStep.WorkflowStepId into acceptedSteps
from acceptedStep in acceptedSteps.DefaultIfEmpty()
join rejectedStep in this.Repository.Context.Set<CompanyWorkflowStep>() on userStep.RejectedStepId equals rejectedStep.WorkflowStepId into rejectedSteps
from rejectedStep in rejectedSteps.DefaultIfEmpty()
let step =
message.InboxEntryType == InboxEntryType.Claims ||
message.InboxEntryType == InboxEntryType.AdvancedLeave ||
message.InboxEntryType == InboxEntryType.ChangeRequest
? new WorkflowHeaderStep
{
WorkflowItem = userStep.WorkflowItem,
AcceptedStepId = userStep.AcceptedStepId,
AcceptedStep = acceptedStep == null ? null : new WorkflowStep
{
OnApprovalActionId = acceptedStep.OnApprovalActionId,
OnRejectionAction = acceptedStep.OnRejectionAction,
OrderNumber = acceptedStep.OrderNumber
},
RejectedStepId = userStep.RejectedStepId,
RejectedStep = rejectedStep == null ? null : new WorkflowStep
{
OnApprovalActionId = rejectedStep.OnApprovalActionId,
OnRejectionAction = rejectedStep.OnRejectionAction,
OrderNumber = rejectedStep.OrderNumber
}
}
: null
let employeeName = string.IsNullOrWhiteSpace(message.OBOEmployee.PreferredName)
? message.OBOEmployee.FullName
: message.OBOEmployee.PreferredName + " " + message.OBOEmployee.LastName
where message.EmployeeId == employeeId
orderby message.EffectiveDate
select new EmployeeInboxMessage
{
Message = message,
UserStep = step,
UserId = message.UserId,
UserName = message.User.FullName,
EmployeeName = message.OBOEmployeeId.HasValue
? employeeName
: message.User.FullName,
RelatedPrimaryKey =
message.InboxEntryType == InboxEntryType.Claims ||
message.InboxEntryType == InboxEntryType.AdvancedLeave ||
message.InboxEntryType == InboxEntryType.ChangeRequest
? userStep.RelatedPrimaryKey
: message.UserWorkflowStepId!.Value,
StartUserCompanyId = message.StartUser.CompanyId
}).ToListAsync();
}
public异步任务GetEmployeeMessagesAsync(长employeeId)
{
返回等待(来自this.Repository.Set中的消息)
将message.UserWorkflowStepId等于userStep.UserWorkflowStepId的.Repository.Context.Set()中的userStep连接到userSteps中
来自userSteps.DefaultIfEmpty()中的userStep
将userStep.AcceptedStepId等于acceptedStep.WorkflowStepId的.Repository.Context.Set()中的acceptedStep加入acceptedSteps
从acceptedSteps.DefaultIfEmpty()中的acceptedStep
将userStep.RejectedStepId上的.Repository.Context.Set()中的rejectedStep连接到rejectedSteps中等于rejectedStep.WorkflowStepId
从rejectedSteps.DefaultIfEmpty()中的rejectedStep
让开=
message.InboxEntryType==InboxEntryType.Claimes||
message.InboxEntryType==InboxEntryType.AdvancedLeave||
message.InboxEntryType==InboxEntryType.ChangeRequest
?新的WorkflowHeaderStep
{
WorkflowItem=userStep.WorkflowItem,
AcceptedStepId=userStep.AcceptedStepId,
AcceptedStep=AcceptedStep==null?null:新工作流步骤
{
OnApprovalActionId=acceptedStep.OnApprovalActionId,
OnRejectionAction=acceptedStep.OnRejectionAction,
OrderNumber=acceptedStep.OrderNumber
},
RejectedStepId=userStep.RejectedStepId,
RejectedStep=RejectedStep==null?null:新工作流步骤
{
OnApprovalActionId=rejectedStep.OnApprovalActionId,
OnRejectionAction=rejectedStep.OnRejectionAction,
OrderNumber=rejectedStep.OrderNumber
}
}
:null
让employeeName=string.IsNullOrWhiteSpace(message.OBOEmployee.PreferredName)
?message.OBOEmployee.FullName
:message.OBOEmployee.PreferredName+“”+message.OBOEmployee.LastName
其中message.EmployeeId==EmployeeId
orderby message.EffectiveDate
选择new EmployeeInboxMessage
{
消息=消息,
UserStep=step,
UserId=message.UserId,
用户名=message.User.FullName,
EmployeeName=message.OBOEmployeeId.HasValue
?雇员姓名
:message.User.FullName,
相关主键=
message.InboxEntryType==InboxEntryType.Claimes||
message.InboxEntryType==InboxEntryType.AdvancedLeave||
message.InboxEntryType==InboxEntryType.ChangeRequest
?userStep.RelatedPrimaryKey
:message.UserWorkflowStepId!。值,
StartUserCompanyId=message.StartUser.CompanyId
}).ToListAsync();
}
对于EF来说,创建单个CompiledQueryCache对象的查询似乎太复杂了,它正在为您传递的每个“employeeId”添加缓存版本。看起来已经有27804个版本了
如果您重新构造查询,那么它可能会解决您的问题。尝试删除“let step=…”和“let employeeName=…”。最糟糕的情况是,您需要创建原始SQL或视图
没有太多文档说明EF如何创建查询缓存(我找不到任何文档)。你可能永远不会知道你的问题到底是什么,除非一些EF创建者提供一些输入,或者你可以随时查看他们的代码
如果在更改查询后仍有问题,最好使用efcore记录问题。更新到EF Core 3.x或5.2。查询结果不由EF Core本身缓存3。如果您仍然有问题,请将问题发布到EF Core存储库。不幸的是,我们有一个活动系统,不能只更新到Core 3。但我们正在更新。如果E core没有缓存查询,它是什么?文档声明“缓存结果,因此不需要每次执行查询时都进行此处理”仅缓存具有PK的实体。如果您对此有问题,请始终重新创建DataContext。在.netcore中,您可以通过依赖项注入注册DBContext。至少这是默认行为。您还将其注册为作用域,这意味着将在每个请求上创建DBContext。所以我不需要重新创建它