Here I am trying to invoke DbContext
object asynchronously from my method. Does it make any performance impact? I know that Entity Framework is not thread safe.
private async Task HasPreviousRecords(long passengerid, long segmentid, short legnumber, long inventoryLegid, string unitdesignator)
{
var defaultTime = Convert.ToDateTime("9999-12-31 00:00:00.000");
var records = _baseContext.PassengerJourneyLegVersions.Select(s => s).Where(s =>
s.VersionEndUTC != defaultTime &&
s.LiftStatus.Equals(1) &&
s.UnitDesignator != string.Empty &&
s.InventoryLegID.Equals(inventoryLegid) &&
s.LegNumber.Equals(legnumber) &&
s.SegmentID.Equals(segmentid) &&
s.PassengerID.Equals(passengerid)).ToList().OrderByDescending(s => s.VersionStartUTC).FirstOrDefault();
if (records != null)
{
if (unitdesignator != records.UnitDesignator)
{
var passengerJourneryLeg = new PassengerJourneryLeg()
{
InventoryLegid = Convert.ToInt32(inventoryLegid),
Legnumber = Convert.ToInt32(legnumber),
Passengerid = Convert.ToInt32(passengerid),
Segmentid = Convert.ToInt32(segmentid)
};
await PushMessageToQueue(passengerJourneryLeg);
}
}
}
The context class has singleton lifetime of dependency.
CodePudding user response:
It is a common misconception that asynchronous operations will perform "faster", or have lower latency than synchronous operations. This is incorrect. Async calls will typically introduce a tiny (sometimes immeasurable) amount of additional latency due to the creation of the async state machine and the cost of queueing up continuations.
That said, what you gain from an asynchronous I/O in your application is significant improvements in throughput. By not tying up threads with blocking I/O calls, those threads are now free to do more work, leading to greater throughput for your application.
Entity Framework Core provides async variants of common deferred execution methods that must be awaited (ToListAsync
vs ToList
or FirstOrDefaultAsync
vs FirstOrDefault
) and should be used when switching to async.
In addition, when querying your context, you want to avoid projecting the entire collection into memory when you only need one record. The following snippet adds several optimizations:
- It switches from sync to async
- It removes the unnecessary .Select call
- It stops projecting the entire collection in memory and executes a
select top 1
query on the database side instead
private async Task HasPreviousRecords(long passengerid, long segmentid, short legnumber, long inventoryLegid, string unitdesignator)
{
var defaultTime = Convert.ToDateTime("9999-12-31 00:00:00.000");
var records = await _baseContext.PassengerJourneyLegVersions
.Where(s =>
s.VersionEndUTC != defaultTime &&
s.LiftStatus.Equals(1) &&
s.UnitDesignator != string.Empty &&
s.InventoryLegID.Equals(inventoryLegid) &&
s.LegNumber.Equals(legnumber) &&
s.SegmentID.Equals(segmentid) &&
s.PassengerID.Equals(passengerid))
.OrderByDescending(s => s.VersionStartUTC)
.FirstOrDefaultAsync();
if (records != null)
{
if (unitdesignator != records.UnitDesignator)
{
var passengerJourneryLeg = new PassengerJourneryLeg()
{
InventoryLegid = Convert.ToInt32(inventoryLegid),
Legnumber = Convert.ToInt32(legnumber),
Passengerid = Convert.ToInt32(passengerid),
Segmentid = Convert.ToInt32(segmentid)
};
await PushMessageToQueue(passengerJourneryLeg);
}
}
}
Please note that DbContext absolutely should NOT be a singleton. It should be Scoped or Transient and should be disposed at the end of every context usage.
CodePudding user response:
It's OK to use an EF context in an asynchronous method but you need to ensure that any methods that may run in parallel are not using the same context.