1.以下代码存在内存泄漏(注意:该代码只有结合EF使用才会存在)
// 组装表达式目录树
Type type = = repositoryEntity.GetType();
ParameterExpression parameterExpression = Expression.Parameter(type, "t");
// 生成条件表达式
BinaryExpression binaryExpression = null;
// 采集文件Id
var acquisitionIdProp = type.GetProperty(nameof(RestingEcgReportFileRelationEntity.AcquisitionFileId));
var acquisitionIdValue = acquisitionIdProp?.GetValue(repositoryEntity);
if (acquisitionIdValue != null)
{
// 定义表达式成员
MemberExpression memberExpression = Expression.Property(parameterExpression, acquisitionIdProp);
// 表达式中且 &&
binaryExpression = Expression.Equal(memberExpression, Expression.Constant(acquisitionIdValue, typeof(long)));
}
// 报告Id
var reportIdProp = type.GetProperty(nameof(RestingEcgReportFileRelationEntity.ReportId));
var reportIdValue = reportIdProp?.GetValue(repositoryEntity);
if (reportIdValue != null)
{
// 定义表达式成员
MemberExpression memberExpression = Expression.Property(parameterExpression, reportIdProp);
// 表达式中且 &&
if (binaryExpression != null)
{
binaryExpression = Expression.AndAlso(binaryExpression, Expression.Equal(memberExpression, Expression.Constant(reportIdValue, typeof(long))));
}
else
{
binaryExpression = Expression.Equal(memberExpression, Expression.Constant(reportIdValue, typeof(long)));
}
}
TEntity singleEntity = default(TEntity);
// 根据采集文件Id 和报告Id查询
if (binaryExpression != null)
{
var expression = Expression.Lambda<Func<TEntity, bool>>(binaryExpression, new ParameterExpression[1] { parameterExpression });
Logger.LogInformation("表达式目录树执行完成");
singleEntity = GetSingle(ServiceProvider, expression, true);
}
// 根据Id 查询
else
{
singleEntity = GetSingle<TEntity>(ServiceProvider, t => t.Id == repositoryEntity.Id, true);
}
泄漏原因是赋值时使用了 Expression.Constant(reportIdValue, typeof(long))
主要原因是EFCore 对表达式内部使用了缓存处理,直接赋值常量表达式值的时候,缓存结果相当于保存对应的结果值,因此命中缓存的概率很低,所以会出现每次执行不同的表达式时会进行一次缓存;解决方案:将常量表达式改为表达式目录树参数化格式进行处理,这样每次的表达式参数化结构都是固定的,不会出现同一套查询条件格式,多次缓存的情况,将代码调整如下:
Expression<Func<long>> idExpression = () => IdValue.ToLongOrDefault();
完整代码如下:
// 组装表达式目录树
Type type = repositoryEntity.GetType();
ParameterExpression parameterExpression = Expression.Parameter(type, "t");
// 生成条件表达式
BinaryExpression binaryExpression = null;
// 采集文件Id
var acquisitionIdProp = type.GetProperty(nameof(RestingEcgReportFileRelationEntity.AcquisitionFileId));
var acquisitionIdValue = acquisitionIdProp?.GetValue(repositoryEntity);
if (acquisitionIdValue != null)
{
Expression<Func<long>> idExpression = () => acquisitionIdValue.ToLongOrDefault();
// 定义表达式成员
MemberExpression memberExpression = Expression.Property(parameterExpression, acquisitionIdProp);
// 表达式中且 &&
binaryExpression = Expression.Equal(memberExpression, idExpression.Body);
}
// 报告Id
var reportIdProp = type.GetProperty(nameof(RestingEcgReportFileRelationEntity.ReportId));
var reportIdValue = reportIdProp?.GetValue(repositoryEntity);
if (reportIdValue != null)
{
Expression<Func<long>> idExpression = () => reportIdValue.ToLongOrDefault();
// 定义表达式成员
MemberExpression memberExpression = Expression.Property(parameterExpression, reportIdProp);
// 表达式中且 &&
if (binaryExpression != null)
{
binaryExpression = Expression.AndAlso(binaryExpression, Expression.Equal(memberExpression, idExpression.Body));
}
else
{
binaryExpression = Expression.Equal(memberExpression, idExpression.Body);
}
}
TEntity singleEntity = default(TEntity);
// 根据采集文件Id 和报告Id查询
if (binaryExpression != null)
{
var expression = Expression.Lambda<Func<TEntity, bool>>(binaryExpression, new ParameterExpression[1] { parameterExpression });
Logger.LogInformation("表达式目录树执行完成");
singleEntity = GetSingle(ServiceProvider, expression, true);
}
// 根据Id 查询
else
{
singleEntity = GetSingle<TEntity>(ServiceProvider, t => t.Id == repositoryEntity.Id, true);
}