I have three tables in EF Core code-first database which have a one-to-many-to-one relationship:
public class Operator
{
[Key]
public string Username { get; set; }
public string PhoneNumber { get; set; }
public List<Ticket> Tickets { get; set; }
}
public class Ticket
{
public int TicketId { get; set; }
public DateTime Date { get; set; }
public int LotNumber { get; set; }
public enum TicketStatus { get; set; }
// navigation properties
public Specification Specification { get; set; }
// foreign keys
public string OperatorUsername { get; set; }
public int SpecificationId { get; set; }
}
public class Specification
{
public int SpecificationId { get; set; }
public int Wages { get; set; }
public string ColorName { get; set; }
public string SizeName { get; set; }
public string Description { get; set; }
}
As you can see, one operators can have many tickets, also one specification can have many tickets.
However in one specification we can have hundreds to thousands of tickets. The problem is right now I want to fetch data using EF Core starting from operators to check for all the the tickets that the operator has attended and what is the specification for the tickets.
So this is inside my controller right now.
public Task<Operator> GetOperatorWithTickets(Username)
{
return await context.Operator
.Include(x => x.Tickets)
.ThenInclude(y => y.Specification)
.FirstOrDefaultAsync(c => c.Username == Username);
}
However after inspecting the query that EF Core generated, I find that EF Core uses join query to get all three tables together, and I think it might not be very efficient to keep scanning table Specification
for every single tickets in join query.
I am considering this method using FindAsync
to reuse existing tracked Specification
entities
public Task<Operator> GetOperatorWithTickets(Username)
{
Operator Operator await context.Operator
.Include(x => x.Tickets)
.FirstOrDefaultAsync(c => c.Username == Username);
foreach (Ticket ticket in Operator.Tickets)
{
ticket.Specification = await context.ticket.FindAsync(ticket.SpecificationId);
}
return Operator;
}
I believe second method can reduce database overhead because database scan for table Specification
will only be performed when the entity Specification is not yet retrieve for all previous any tickets, else the existing entities will be used again and again for hundreds or even thousands of tickets that share same specification.
I am still a novice and not sure about all the caching that database might performs to reduce the overhead in first method, so in my view second method should outperforms the first method. What is your view on this? Should I stick with the first methods or migrate to second methods?