I think that what you ask is answered in the docs:
|Unit of Work and Async
The Unit of work classes are also async aware and have been updated with async variants of some of their methods. Using the unit of work classes hasn't changed, only the way to commit the unit of work, using CommitAsync. CommitAsync is equal to Commit, however it's an asynchronous method which can be awaited and which performs all its actions asynchronously:
- Opening the connection is asynchronous (adapter)
- Every element to execute is executed asynchronously, except stored procedure calls and callbacks.
Transaction create, commit/rollback are synchronous as there's no ADO.NET way to do these actions asynchronously. All actions taken by the unit of work are done asynchronously and the results are awaited before the next action is performed.
Synchronous code used by asynchronous methods
Saving an entity asynchronously and refetching it will do the save part (insert or update) asynchronously but will do the fetch part synchronously. This is because the fetch uses the FetchEntity method on adapter and a call to a generated method in SelfServicing, requiring more code to be ported / copied to make things async than reasonable, so we left that synchronously. Fetches of entities are single row returning queries using PK filters, so the queries should execute very quickly and the delay be minimal, so making this piece of the pipeline asynchronous wouldn't make things behave that differently, hence we left it as-is.
TransactionScope and Async
Although the API supports TransactionScope/System.Transactions, it's mandatory that the code which creates the TransactionScope and which has one or more await statements inside the TransactionScope, has a valid SynchronizationContext active on the current thread. If not, the TransactionScope will fail, because it's being disposed on another thread due to the await statement. This is a general aspect of asynchronous programming and .NET and not something we can avoid.