I am building a REST API using C#.NET for a customer, which will be used to retrieve error logs from a database. The database has three tables: Fault, Message and MessageData. The relation of the tables are as follows:
Fault <---* Message <---1 MessageData
Meaning one Fault can have multiple messages linked to it from the Message table, which in turn can have one message data linked to it from the MessageData table.
I have created Entity Models representing these tables using Entity Framework Core. I have also created DTOs for each Entity Model, containing only the data that is relevant to transfer over the wire. In my repository class, I am using LINQ to write a query to the database, mapping the result over to my DTOs from my Entity Models.
My question is whether this code can be rewritten to be more sufficient, specially in terms of deferred execution (not wanting to make any unnessecary roundtrips to the database):
public async Task<IEnumerable<FaultDTO>> GetFaultsAsync(string? application, DateTime? fromDate, DateTime? toDate, int? count)
{
List<FaultDTO> faults;
fromDate = (fromDate == null) ? DateTime.Today.AddDays(-30) : fromDate;
toDate = (toDate == null) ? DateTime.Today : toDate;
count = (count == null) ? 10 : count;
faults = await _context.Faults.Where(fault => String.IsNullOrWhiteSpace(application) ? fromDate <= fault.InsertedDate && fault.InsertedDate <= toDate : fault.Application.ToLower() == application.ToLower() && fromDate <= fault.InsertedDate && fault.InsertedDate <= toDate).Select(fault => new FaultDTO()
{
FaultId = fault.FaultId,
InsertedDate = fault.InsertedDate,
MachineName = fault.MachineName,
ServiceName = fault.ServiceName,
Scope = fault.Scope,
FaultDescription = fault.FaultDescription,
Messages = _context.Messages.Where(msg => fault.FaultId == msg.FaultId).Select(msg => new MessageDTO()
{
MessageId = msg.MessageId,
MessageName = msg.MessageName,
MessageData = _context.MessageData.Where(msgData => msg.MessageId == msgData.MessageId).Select(msgData => new MessageDataDTO()
{
MessageData = msgData.MessageData,
MessageId = msgData.MessageId
}).SingleOrDefault(),
FaultId = fault.FaultId,
}).ToList()
}).OrderByDescending(fault => fault.InsertedDate).Take((int)count).ToListAsync<FaultDTO>();
return faults;
}
Also if someone could clarify if the query executed against the database at the end ('.ToListAsync();'), or is it executed partially three times at this stages: '.ToList()', '.SingleOrDefault()' and '.ToListAsync()?
As mentioned, the main focus is deferred execution. This being said, I will happily receive any suggestion for optimizing my code in terms of performance in general.