0

Consider this model. Basically what I'm trying to do is obtaining every door in the table 'doors' such that there exists a corresponding entry in the table 'doors_to_devices' with a given device_id.

Here's what I've been trying

public async Task<ServiceResponse<AuthorizedDoorsDto>> Authenticate(string username, string password)
{
    // Irrelevant code
    var device = await dataContext.Devices
                           .Include(d => d.DoorsToDevices)
                           .FirstOrDefaultAsync(d => d.Username == username && d.Password == password);

    var doors = await dataContext.Doors
                         .Where(d => d.DoorsToDevices.ToList().ForEach(dtd => dtd.DeviceId.Equals(device.Id)));
    // More irrelevant code
}

But this obviously doesn't work...

I've actually got it to work some other way, in a previous version of the code (slightly different in purpose), but it seems so convoluted, I was hoping there was a simpler way. Here's how I got it to work:

private async Task<List<DoorDto>> GetDeviceDoors(Device device)
{
    var doorsToDevice = device.DoorsToDevices.ToList();

    List<Guid> doorsIds = new List<Guid>();

    doorsToDevice.ForEach(dtd => doorsIds.Add(dtd.DoorId));

    var doors = await _dataContext.Doors
                                  .Where(d => doorsIds.Contains(d.Id))
                                  .IgnoreAutoIncludes()
                                  .ToListAsync();
    var doorDtos = new List<DoorDto>();

    foreach (var door in doors)
    {
        doorDtos.Add(_mapper.Map<DoorDto>(door));
    }

    return doorDtos;
}

public async Task<ServiceResponse<AuthenticateDto>> Authenticate(string username, string password, Guid id)
{
    // Irrelevant code
    
    var device = await _dataContext.Devices
                            .Include(d => d.DoorsToDevices)
                            .FirstOrDefaultAsync(d => d.Id == id);
    var doors = GetDeviceDoors(device).Result;

    // More irrelevant code
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 1
    Why not just join through the navigation properties? `.Doors.Where(d => d.DoorsToDevices.Any(dtd => dtd.Device.UserName == username && dtd.Device.Password == password))` – Jeremy Lakeman May 10 '21 at 01:11
  • Did you use virtual property references? You can find it from here https://stackoverflow.com/questions/8542864/why-use-virtual-for-class-properties-in-entity-framework-model-definitions – Nileksh Dhimer May 10 '21 at 04:09
  • @JeremyLakeman your tip was precious! Feel free to answer this post. I will check it! – CuriousCharlie May 11 '21 at 23:40

1 Answers1

1

Instead of collecting keys from one table, to include in the where clause of another table. Why not just join through directly in your query, via navigation properties;

var doors = await dataContext.Doors
    .Where(d => d.DoorsToDevices
        .Any(dtd => dtd.Device.UserName == username
            && dtd.Device.Password == password)
    )
    .ToListAsync();
Jeremy Lakeman
  • 9,515
  • 25
  • 29