Search code examples
c#.netdatabaseentity-frameworkcqrs

HasValue invalidates EF query


The issue with the current query (the one below) is if request.DepartmentId.HasValue is false. All I want it to do is basically to find the available rooms within the period from "From" to "To" that belong to DepartmentId and RoomType matches too.

public async Task<Response> Handle(GetAvailableRoomsQuery request, CancellationToken cancellationToken)
{
    // We are getting all class activities between From and To
    var classActivities = await _sender.Send(
        new GetClassActivitiesQuery
        {
            From = request.From,
            To = request.To
        }, cancellationToken);

    // finding all unavailable rooms between From and To
    var unavailableRoomIds = new HashSet<int>(classActivities.Select(e => e.RoomId));

    return await _context.Rooms
        .Where(room => !unavailableRoomIds.Contains(room.Id) &&
                        request.DepartmentId.HasValue && request.DepartmentId.Value == room.DepartmentId &&
                        request.RoomType.HasValue && request.RoomType.Value == room.Type)
        .ProjectTo<RoomDto>(_mapper.ConfigurationProvider)
        .ToListAsync(cancellationToken);
}

This was the previous query that used to work, but 3 Where statements.

public async Task<Response> Handle(GetAvailableRoomsQuery request, CancellationToken cancellationToken)
{
    var classActivities = await _sender.Send(
        new GetClassActivitiesQuery
        {
            From = request.From,
            To = request.To
        }, cancellationToken);

    var unavailableRoomIds = new HashSet<int>(classActivities.Select(e => e.RoomId));

    return await _context.Rooms
        .Where(room => !unavailableRoomIds.Contains(room.Id))
        .Where(room => !request.DepartmentId.HasValue || request.DepartmentId.Value == room.DepartmentId)
        .Where(room => !request.RoomType.HasValue || request.RoomType.Value == room.Type)
        .ProjectTo<RoomDto>(_mapper.ConfigurationProvider)
        .ToListAsync(cancellationToken);
}

Solution

  • As mentioned by @juharr:

    return await _context.Rooms
        .Where(room => !unavailableRoomIds.Contains(room.Id))
        .Where(room => !request.DepartmentId.HasValue || request.DepartmentId.Value == room.DepartmentId)
        .Where(room => !request.RoomType.HasValue || request.RoomType.Value == room.Type)
    

    should be equivalent to:

    return await _context.Rooms
        .Where(room => !unavailableRoomIds.Contains(room.Id)) &&
                      (!request.DepartmentId.HasValue || request.DepartmentId.Value == room.DepartmentId) &&
                      (!request.RoomType.HasValue || request.RoomType.Value == room.Type))
    

    Don't really get why you changed ||s for &&s and removed !s