C# LINQ 多行条件

C# LINQ Multiple Line Conditions

提问人:Batug Kocak 提问时间:11/8/2023 最后编辑:Batug Kocak 更新时间:11/8/2023 访问量:100

问:

public List<VehicleOnTaskDetailDto> GetVehicleOnTaskDetailFinished(VotFilterRequest filterRequest)
{
    using VehicleDeliveryContext context = new VehicleDeliveryContext();
    var result = (from v in context.VehiclesOnTask
        join d in context.Departments on v.DepartmentId equals d.Id 
        join dr in context.Drivers on v.DriverId equals dr.Id
        join vehicle in context.Vehicles on v.VehicleId equals vehicle.Id 
        where v.IsDeleted != true
        where v.IsFinished == true
        orderby v.GivenDate descending 
        select new VehicleOnTaskDetailDto{
            VehicleOnTaskId = v.Id,
            VehiclePlate = vehicle.Plate,
            VehicleId = v.VehicleId,
            DriverName = $"{dr.Name} {dr.Surname} - {dr.Mission}",
            DepartmentName = d.Name,
            TaskDefinition = v.TaskDefinition,
            AuthorizedPerson = v.AuthorizedPerson,
            Address = v.Address,
            GivenDate = v.GivenDate,
            ReturnDate = v.ReturnDate
        }).ToList();
    return result;
}

我想添加 2 行代码取决于 VotFilterRequest 自带的 DateType 过滤器,如下所示:

if (filterRequest.DateType == "GivenDate")
{
    where filterRequest.FirstDate <= v.GivenDate
    where filterRequest.LastDate >= v.GivenDate
}
else
{
    where filterRequest.FirstDate <= v.ReturnDate
    where filterRequest.LastDate >= v.ReturnDate
}

我知道你不能这样做,但我也不想重复我的代码。有什么办法可以很快做到这一点吗?谢谢问候。

注意:为了清楚起见,我想使用 LINQ 查询语法,而不是方法语法。

C# .NET 实体框架 LINQ IF语句

评论


答:

2赞 Michał Turczyn 11/8/2023 #1

通过使用 LINQ 扩展方法并在生成查询期间使用,可以轻松实现它:IQueryable

var query = context.VehiclesOnTask
    // You'd need to define those navigation properties.
    .Include(x => x.Department)
    .Include(x => x.Driver)
    .Include(x => x.Vehicle)
    .Where(x => x.IsDeleted == false)
    .Where(x => x.IsFinished == true);
    
query = filterRequest.DateType == "GivenDate"
    ? query.Where(v => filterRequest.FirstDate <= v.GivenDate && filterRequest.LastDate >= v.GivenDate)
    : query.Where(v => filterRequest.FirstDate <= v.ReturnDate && filterRequest.LastDate >= v.ReturnDate);
    
return query
    .OrderByDescending(x => x.GivenDate)
    .Select(v => new VehicleOnTaskDetailDto
    {
        VehicleOnTaskId = v.Id,
        VehiclePlate = vehicle.Plate,
        VehicleId = v.VehicleId,
        DriverName = $"{dr.Name} {dr.Surname} - {dr.Mission}",
        DepartmentName = d.Name,
        TaskDefinition = v.TaskDefinition,
        AuthorizedPerson = v.AuthorizedPerson,
        Address = v.Address,
        GivenDate = v.GivenDate,
        ReturnDate = v.ReturnDate,
    })
    .ToList();

您还可以尝试将筛选器合并到当前查询语法中:

// for better readability we assign condition value to variable:
var isGivenDate = filterRequest.DateType == "GivenDate";
// and incorporate it in the filter.
where (isGivenDate && filterRequest.FirstDate <= v.GivenDate && filterRequest.LastDate >= v.GivenDate) 
    || (!isGivenDate && filterRequest.FirstDate <= v.ReturnDate && filterRequest.LastDate >= v.ReturnDate)

评论

0赞 Batug Kocak 11/8/2023
这将起作用,但如果我使用它,我将放弃使用查询语法并将我的函数转换为方法语法。如果可能的话,我正在尝试将其用作查询语法
0赞 Svyatoslav Danyliv 11/8/2023
为什么要添加 Includes?之后,它们被完全忽略了。Select
0赞 Batug Kocak 11/8/2023
他不是通过添加 Includes 来加入表格吗?
2赞 Krzysztof Skowronek 11/8/2023
@BatugKocak 我认为你是真正喜欢查询语法的五个人之一。然后你非常努力地用 C# 编写 SQL,当您可以使用良好的旧 LINQ 方法语法时,将 include 和永远忘记 join。
0赞 Batug Kocak 11/9/2023
我实际上喜欢 SQL 和 C# 以及 LINQ 的新方法,所以这就是为什么我更喜欢查询语法,但如果每个人都使用方法语法,也许我也应该这样做!
1赞 Javad J 11/8/2023 #2

Expression<Func<T, bool>> 可以在 Where() 方法中实例化和使用,您必须在查询之前创建此实例:

Expression<Func<VehicleOnTaskDetailDto, bool>> filter;
if (filterRequest.DateType == "GivenDate") {
    filter = 
        en =>
         filterRequest.FirstDate <= en.GivenDate
         && filterRequest.LastDate >= en.GivenDate;
}
else
{
    filter = 
        en =>
         filterRequest.FirstDate <= en.ReturnDate
          && filterRequest.LastDate >= en.ReturnDate;

}

并在以下条件中使用此过滤器:

...
.Where(filter)
...

注意: 三元条件也是一个很好的方法,感谢 Michał Turczyn 的回答。

评论

0赞 Batug Kocak 11/8/2023
如果我合并你的两个代码,那会起作用并且实际上看起来不错,但我想使用查询语法。无论如何,感谢您的回答!
1赞 Svyatoslav Danyliv 11/8/2023 #3

您可以使用混合方法,使用它们向记录集添加筛选器。简单来说,使用方法语法更简单:where

public List<VehicleOnTaskDetailDto> GetVehicleOnTaskDetailFinished(VotFilterRequest filterRequest)
{
    using var context = new VehicleDeliveryContext();

    var vehiclesOnTask = context.VehiclesOnTask.AsQueryable();

    if (filterRequest.DateType == "GivenDate")
    {
        vehiclesOnTask = vehiclesOnTask.Where(v => filterRequest.FirstDate <= v.GivenDate && filterRequest.LastDate >= v.GivenDate)
    }
    else
    {
        vehiclesOnTask = vehiclesOnTask.Where(v => filterRequest.FirstDate <= v.ReturnDate && filterRequest.LastDate >= v.ReturnDate)
    }   

    var result = (from v in vehiclesOnTask
        join d in context.Departments on v.DepartmentId equals d.Id 
        join dr in context.Drivers on v.DriverId equals dr.Id
        join vehicle in context.Vehicles on v.VehicleId equals vehicle.Id 
        where v.IsDeleted != true
        where v.IsFinished == true
        orderby v.GivenDate descending 
        select new VehicleOnTaskDetailDto{
            VehicleOnTaskId = v.Id,
            VehiclePlate = vehicle.Plate,
            VehicleId = v.VehicleId,
            DriverName = $"{dr.Name} {dr.Surname} - {dr.Mission}",
            DepartmentName = d.Name,
            TaskDefinition = v.TaskDefinition,
            AuthorizedPerson = v.AuthorizedPerson,
            Address = v.Address,
            GivenDate = v.GivenDate,
            ReturnDate = v.ReturnDate
        }).ToList();
    return result;
}

评论

0赞 Batug Kocak 11/8/2023
它会自动将首先 where 方法(在 if-else 语句中)应用于下面的查询吗?
1赞 Svyatoslav Danyliv 11/8/2023
是的,这就是 LINQ 转换器的工作方式。请注意,我已将您的查询更改为使用变量。vehiclesOnTask