[英]C# EF Core QueryableExtensions.FirstOrDefaultAsync strange behaviour
我有一个通用存储库,将Expression<Func<TEntity, bool>> filter
传递给该通用存储库。 例如,此表达式如下所示:
filterExpr = part =>
(filter.ProductId != null ? filter.ProductId == part.ProductId : true) &&
(filter.SerialNumber != null ? filter.SerialNumber == part.SerialNumber : true);
在存储库中,我从DbContext获得的DbSet上调用QueryableExtensions.FirstOrDefaultAsync(filterExpr)
filterExpr):
this.dbSet = context.Set<TEntity>()
// ....
IQueryable<TEntity> query = dbSet;
return query.FirstOrDefaultAsync(filter);
如果定义了ProductId
或SerialNumber
或同时定义了两者,则效果很好。 如果所有过滤器属性均为null
,则我希望表达式的计算结果为true
,因此FirstOrDefaultAsync
返回查询表中的第一个Element。 但是相反,EF内核似乎试图加载整个表。 我的内存消耗上升了几GB,然后收到超时。 当我使用InMemoryDatabase执行UnitTest时,结果为null
,这也不是我所期望的。
编辑:这是根据要求的UnitTest。
[Fact]
public void GetPartWithEmptyFilterTest()
{
var optionsBuilder = new DbContextOptionsBuilder<ProductStatusContext>();
optionsBuilder.UseInMemoryDatabase("GetPartWithEmptyFilterTest");
var context = new ProductStatusContext(optionsBuilder.Options);
var part = new Part { SerialNumber = "abcdef" };
context.Parts.Add(part);
context.SaveChanges();
var unitOfWork = new UnitOfWork(context);
var service = new PartService(unitOfWork, null, null);
service.GetPartAsync(new PartFilterResource()).Result.Should().Be(part);
}
EDIT2:我目前的解决方法是测试所有过滤器属性为null
值和评估过滤接只有当至少在属性为从不同null
private bool AllPropertiesNull(object obj)
{
return !obj.GetType().GetProperties().Any(propInfo => propInfo.GetValue(obj) != null);
}
接着:
if(filter != null && AllPropertiesNull(filter))
filterExp = part => true;
但我想避免这种情况。
根据我在EF Core上的经验,查询翻译器试图消除常量谓词表达式,以便产生类似于(如果没有条件的话)条件的条件(如果您使用条件条件Where
。
但是,它似乎可以正确处理二进制表达式( &&
, ||
),并且对条件条件无法执行此操作? :
? :
表达式。 您可以将其报告给他们的GitHub问题跟踪器,但是由于他们正在使用EF Core 3.0,因此我认为在早期版本中不会解决该问题。 而且3.0仍然处于无法执行许多操作的状态,因此无法用于评估在最终版本中是否可行。
我建议的解决方法(似乎在所有版本中均能正常工作)是使用等效的||
基于条件,例如
filterExpr = part =>
(filter.ProductId == null || filter.ProductId == part.ProductId) &&
(filter.SerialNumber == null || filter.SerialNumber == part.SerialNumber);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.