如何否定IQueryable的Where子句

时间:2017-02-21 13:59:23

标签: c# entity-framework linq iqueryable

我创建了一个扩展方法来封装一些 where 这样的逻辑(这是一个非常简化的版本):

public static IQueryable<Cargo> ReadyToCarry(this IQueryable<Cargo> q)
{
    VehicleType[] dontNeedCouple = new VehicleType[] { VehicleType.Sprinter, VehicleType.Van, VehicleType.Truck };

    return q.Where(c => c.DriverId > 0 && c.VehicleId > 0)
            .Where(c => c.CoupleId > 0 || dontNeedCouple.Contains(c.Vehicle.Type));
}

所以我可以这样使用它:

using (var ctx = new MyNiceContext())
{
    var readyCargo = ctx.Cargos.ReadyToCarry().OrderBy(c => c.Id).ToList();
    // ...more code
}

这很好用,它被翻译为 SQL 并由 Entity Framework 执行。现在,我还有另一个地方需要货物,这些货物还没有准备好携带,这意味着我需要恰恰相反。

我的想法是这样的:

public static IQueryable<Cargo> NotReadyToCarry(this IQueryable<Cargo> q)
{
    return !q.ReadyToCarry(); // ofc this doesn't work...
}

using (var ctx = new MyNiceContext())
{
    var readyCargo = ctx.Cargos.NotReadyToCarry().OrderBy(c => c.Id).ToList();
    // OR maybe
    var readyCargo = ctx.Cargos.ReadyToCarry(false).OrderBy(c => c.Id).ToList(); // somehow use that bool param to reverse the logic when false
}

我不想从头开始重新创建反向逻辑,所以如果有一天我需要更改它,我会在一个独特的地方进行更改。

我接受这种方法的替代方案,因为它是一个新项目。

1 个答案:

答案 0 :(得分:6)

您可以使用Except()方法:

var readyCargo = ctx.Cargos.ReadyToCarry().OrderBy(c => c.Id);
var notReadyCargo = ctx.Cargos.Except(readyCargo);

您可以在ReadyToCarry()中添加一些参数:

public static IQueryable<Cargo> ReadyToCarry(this IQueryable<Cargo> q, bool ready = true)
{
    VehicleType[] dontNeedCouple = new VehicleType[] { VehicleType.Sprinter, VehicleType.Van, VehicleType.Truck };

    if (ready)
    {
        return q.Where(c => c.DriverId > 0 && c.VehicleId > 0)
                .Where(c => c.CoupleId > 0 || dontNeedCouple.Contains(c.Vehicle.Type));
    }
    else
    {
        // logic to get not ready for carrying
    }
}

您可以将这两个选项结合起来:

public static IQueryable<Cargo> ReadyToCarry(this IQueryable<Cargo> q, bool ready = true)
{
    VehicleType[] dontNeedCouple = new VehicleType[] { VehicleType.Sprinter, VehicleType.Van, VehicleType.Truck };

    var readyToCarry = q.Where(c => c.DriverId > 0 && c.VehicleId > 0)
                        .Where(c => c.CoupleId > 0 || dontNeedCouple.Contains(c.Vehicle.Type));

    if (ready)
    {
        return readyToCarry;
    }
    else
    {
        return q.Except(readyToCarry);
    }
}

在最后一种情况下,当您更改逻辑以准备携带实体时,您不需要更改对该条件的否定。您应该只更改一个查询。