c# - C# EF Core QueryableExtensions.FirstOrDefaultAsync 奇怪的行为
问题描述
我有一个通用存储库,我将Expression<Func<TEntity, bool>> filter
. 例如,这个表达式看起来像:
filterExpr = part =>
(filter.ProductId != null ? filter.ProductId == part.ProductId : true) &&
(filter.SerialNumber != null ? filter.SerialNumber == part.SerialNumber : true);
在存储库QueryableExtensions.FirstOrDefaultAsync(filterExpr)
中,我调用了从 DbContext 获得的 DbSet:
this.dbSet = context.Set<TEntity>()
// ....
IQueryable<TEntity> query = dbSet;
return query.FirstOrDefaultAsync(filter);
ProductId
如果定义了一个或SerialNumber
两个,它会很好地工作。如果所有过滤器属性都是null
,我希望表达式的计算结果为true
并因此FirstOrDefaultAsync
返回查询表中的第一个元素。但相反,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);
推荐阅读
- python - 如何使用 scipy.curve_fit 将 Python 中的实验数据拟合到定义区域有限的反三角函数?
- java - JavaFX:TableView 使用 ObservableList 中的特定数据填充列
- javascript - 服务器节点代理中未发生 api 调用
- c# - 表示字典
在 .NET Core 环境变量中 - server - 我服务器的 crontab 中的这个条目有什么作用?
- c++ - 如何从派生类实例调用父类重载函数?
- android - 我应该为 ConstraintLayout 元素使用约束或大小属性吗?
- kubernetes - kubernetes networkpolicy namespaceSelector 在命名空间没有标签时选择
- c# - ASP.net CRUD WCF AJAX 后调用方法不允许
- kubernetes - 如何与同一节点中另一个 pod 的 daemonset pod 通信?