繁体   English   中英

C#EF核心QueryableExtensions.FirstOrDefaultAsync奇怪的行为

[英]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);

如果定义了ProductIdSerialNumber或同时定义了两者,则效果很好。 如果所有过滤器属性均为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM