【问题标题】:How to write a If condition inside a Where clause in ef core如何在 ef core 的 Where 子句中编写 If 条件
【发布时间】:2022-01-14 21:38:45
【问题描述】:

我正在使用 EF Core 5.0 版的 asp.net 核心 Web API。

我写了一个带有 if 条件的查询。

if (incomingFacilities.Count() > 0)

然后我需要过滤incomingFacilities 列表中的设施。

如果(incomingFacilities.Count() < 0)我不需要过滤。我只需要获得 6 个不同的设施列表。

但是写下面的代码。问题是我需要一次又一次地重复相同的代码。

所以我的东西还是里面的if条件比较好

.Where(x => (incomingFacilities.Count() > 0 ) ? 
            (incomingFacilities.Contains(x.FacilityCode)) :
            (x.FacilityCode > 0 )),

在这里我正确地完成了第一部分,(即:如果incomingFacilities.Count() > 0 然后进行过滤。

但第二部分是if incomingFacilities.Count() < 0,则无需过滤,只需发送设施列表(仅6个设施中的不同)

// this code is correct, but same code repeated 
if (incomingFacilities.Count() > 0)
{
    var hotels = await _context.Hotels
        .Where(i => (i.DestinationCode == request.Destination))
        .Select(i => new HotelListHotelVm
        {
            // removed some
            HotelFacilities =  i.Facilities.Select(x => new HotelListHotelVm.HotelListFacilityVm {
            Id = x.Id,
            FacilityGroupCode = x.FacilityGroupCode,
            HotelFacilityGroupDescription = x.FacilityGroup.Description,
            FacilityCode = x.FacilityCode
        })
        .Where(x => (incomingFacilities.Count() > 0 ) ? (incomingFacilities.Contains(x.FacilityCode)) : (x.FacilityCode > 0 )),
        })
        // rest
        ;
}
else
{
    var hotels = await _context
        .Hotels
        .Where(i => (i.DestinationCode == request.Destination))
        .Select(i => new HotelListHotelVm
        {
            // removed some
            HotelFacilities = i.Facilities.ToList().Distinct().Take(6)           
                .Select(x => new HotelListHotelVm.HotelListFacilityVm {          
                    Id = x.Id,                                                      
                    FacilityGroupCode = x.FacilityGroupCode,                                                     
                    HotelFacilityGroupDescription = x.FacilityGroup.Description,          
                    FacilityCode = x.FacilityCode                                           
                })
        })
        // rest
        ;
}

.Where(x =>(incomingFacilities.Count() > 0 ) ? (incomingFacilities.Contains(x.FacilityCode)) : (x.FacilityCode > 0 )), 这里,

然后我做了If incomingFacilities.Count() > 0,使用 where 子句。

但我不知道怎么说,如果 incomingFacilities.Count() > 0 然后列出具有不同价值的设施,只取6 个。像这样HotelFacilities = i.Facilities.ToList().Distinct().Take(6)

    .Select(x => new HotelListHotelVm.HotelListFacilityVm {          
        Id = x.Id,                                                      
        FacilityGroupCode = x.FacilityGroupCode,                                                     
        HotelFacilityGroupDescription = x.FacilityGroup.Description,          
        FacilityCode = x.FacilityCode                                           
    })

【问题讨论】:

    标签: c# entity-framework linq if-statement entity-framework-core


    【解决方案1】:

    EF Core 查询翻译器足够智能,可以评估使用纯客户端参数的表达式并提前删除已知为 true 的过滤器表达式,例如 true || some_expr

    所以你只需要编写你的过滤器如下:

    .Where(x => !incomingFacilities.Any() || incomingFacilities.Contains(x.FacilityCode))
    

    这将产生两个不同的 SQL 查询 - 一个带有过滤器,另一个不取决于参数 incomingFacilities 是否包含元素。

    【讨论】:

    • 从哪个 EF Core 版本开始?
    • @SvyatoslavDanyliv 如果没记错的话,从 2.0 开始。并在下一个版本中修复/改进。
    • 其实我认为他们总是创建参数。但也许我错过了什么。
    • @SvyatoslavDanyliv 这是我在 EF Core 中喜欢的“酷”东西之一,因为它消除了像在 EF6 中那样构建条件 Where 的需要。我在 2019 年写了以下stackoverflow.com/questions/57520807/…,但很确定它从一开始就存在。不确定他们是否修复了条件运算符,但 ||&& 肯定可以工作。
    • 是的,它有效。看起来他们忘了对 QueryFilter 做同样的事情;)
    【解决方案2】:

    早上好,

    如果我对您的理解正确,您想获得List<HotelListHotelVm>,但如果incomingFacilities 中有元素,则内容会发生变化。

    首先,我将在这里去掉.Count() 扩展名并改用.Any()。这是出于性能原因,因为 .Count() 只会在您遍历整个列表后停止。 .Any() 在您的incomingFacilities 中找到一个元素后停止,如果您的列表中有任何内容,则返回相应的bool。 如果您不需要 incomingFacilities 列表中的项目数并且只检查其中是否有任何内容 .Any() 是更好的选择(就像在您的代码中一样)。如果确实需要计数值,请使用.Count()

    根据您的 cmets,尝试以下方法(同样,未经测试)。首先初始化一个变量,它将您的酒店保存为列表(或数组,或其他)。然后你检查你是否有任何incomingFacilities。如果是这样,您从数据库中获取值并将其与设施代码进行比较。之后,您过滤列表中确实有HotelFacilities 的所有元素。如果其中有一些值,hotels 不为空。

    在下一步中,您将查看hotels 列表。如果其中有值,则不必从数据库中检索任何内容,如果没有,则从数据库中获取前 6 个元素。

    如果incomingFacilities 从一开始就为空,hotels 也是如此,因此代码将从数据库中检索 6 个元素。

    希望我现在理解正确。

    List<HotelListHotelView> hotels = new List<HotelListHotelView>(); 
    
    if (incomingFacilities.Any())
    {
        hotels = await _context.Hotels
                               .Where(i => (i.DestinationCode == request.Destination))
                               .Select(i => new HotelListHotelVm
                               {
                                   HotelFacilities =  i.Facilities.Where(x => incomingFacilities.Contains(x.FacilityCode))
                                                                  .Select(x => new HotelListHotelVm.HotelListFacilityVm 
                                                                                       {
                                                                                           Id = x.Id,
                                                                                           FacilityGroupCode = x.FacilityGroupCode,
                                                                                           HotelFacilityGroupDescription = x.FacilityGroup.Description,
                                                                                           FacilityCode = x.FacilityCode
                                                                                       })
                               }).Where(h => h.HotelFacilities.Any())
                                 .ToList();   
    }
    
    if(!hotels.Any())
    {             
        hotels = await _context.Hotels
                               .Where(i => (i.DestinationCode == request.Destination))
                               .Select(i => new HotelListHotelVm
                               {
                                       HotelFacilities = i.Facilities.Distinct()
                                                                     .Take(6)           
                                                                     .Select(x => new HotelListHotelVm.HotelListFacilityVm 
                                                                         {          
                                                                             Id = x.Id,                                                      
                                                                             FacilityGroupCode = x.FacilityGroupCode,                                                     
                                                                             HotelFacilityGroupDescription = x.FacilityGroup.Description,          
                                                                             FacilityCode = x.FacilityCode                                           
                                                                         })
                               }).ToList();
    }
    

    【讨论】:

    • 嗨,如果incomingFacilities 是[ ],此行HotelFacilities = i.Facilities.Where(x =&gt; incomingFacilities.Contains(x.FacilityCode)) 返回[ ]。但是如果incomingFacilities 是[ ] 我需要6 个HotelFacilities。 (不是 [ ] 或不是所有的酒店设施)
    • 我猜您的i.Facilities 是您从数据库中获得的?所以这一行检查数据库中的某些条目是否是incomingFacilities 的一部分。必须满足这个假设才能得到结果。如果它没有返回任何内容,那么您的传入设施列表中没有任何与数据库相关的条目。我是否正确理解,如果这个假设没有得到满足并且返回值是空/零设施,那么你想获得数据库的前 6 个条目?
    • 如果用户需要过滤我需要发送带有这些设施的酒店的设施,(示例他选择WiFi,那么我需要发送带有WiFi设施的酒店。)否则我需要发送6个设施中的任何一个对于每家酒店。知道了?这就是为什么我问,如果incomingFacilities 为空,那么发送6 家酒店中的任何一家
    • 我更新了代码,现在试试看能否解决你的问题。
    猜你喜欢
    • 2022-06-22
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 2021-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-07
    相关资源
    最近更新 更多