I created an extension method to encapsule some where logic like this (this is a very simplified version):
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));
}
So I can use it like this:
using (var ctx = new MyNiceContext())
{
var readyCargo = ctx.Cargos.ReadyToCarry().OrderBy(c => c.Id).ToList();
// ...more code
}
Which works nicely, this is translated to SQL and executed by Entity Framework. Now, I have another place I need cargos which are not ready to carry, which means I need exactly the opposite.
My idea was something like this:
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
}
I didn't want to recreate the reverse logic from scratch, so if I needed to change it one day, I'd change in one unique place.
I'm accepting alternatives to this approach, since it's a new project.
The IQueryable interface inherits the IEnumerable interface so that if it represents a query, the results of that query can be enumerated. Enumeration causes the expression tree associated with an IQueryable object to be executed.
The major difference between IQueryable and IEnumerable is that IQueryable executes query with filters whereas IEnumerable executes the query first and then it filters the data based on conditions.
IQueryable is executed. // // Returns: // A System.Type that represents the type of the element(s) that are returned when. // the expression tree associated with this object is executed.
IQueryable is suitable for querying data from out-memory (like remote database, service) collections. While querying data from a database, IQueryable executes a "select query" on server-side with all filters. IQueryable is beneficial for LINQ to SQL queries.
You can use Except()
method:
var readyCargo = ctx.Cargos.ReadyToCarry().OrderBy(c => c.Id);
var notReadyCargo = ctx.Cargos.Except(readyCargo);
OR
you can add some parameter to 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
}
}
OR
you can combine these two options:
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);
}
}
In the last case when you change logic to get ready to carry entities you don't need to change negation of that condition. You should change only one query.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With