I don't think you can say "I need to change the design of this without changing the patterns I'm using".
I think you might have a boundary issue if you're doing 20 queries that you can't do in 1 Batch.
Solution 1: Write SQL
SELECT top 10 * FROM database1.dbo.Users;
SELECT top 10 * FROM database2.dbo.Users;
SELECT top 10 * FROM database3.dbo.Users;
SELECT top 10 * FROM database4.dbo.Users;
Execute this as one sproc or command and parse each result into your DTOs.
If you're in MS SQL Server land you can use Linked Servers to cross boundaries. I don't think this is a great idea, but pushes this logic into the DB side and makes it 1 round trip as far as the application is concerns.
Solution 2: Do them concurrently in a Manager
or Helper
Your manager will control getting data from your Repositories.
public class CrossDomainHelper
{
public DTO.User[] Load()
{
IRepo[] rr = new IRepo[]{new RepoA(), new RepoB(), new RepoC(), new RepoD()… new RepoX()};
var tasksToRun = rr.Select( r => r.Get10UsersAsync() ); // Do not await here
var repoCompletions = await Task.WhenAll(tasksToRun);
foreach(var c in repoCompletions)
{
DTO.User[] users = c;
// Do something with them
}
}
}
Solution 3: You need a DataWarehouse or some sort of Aggregation
If you're doing a bunch of queries all over the place that should be part of a single process, then create a single place for that.
Another SQL Server database that collects this information. Maybe events in that update it's state. The structure of this should be suited to the business question you are answering.
You could use CDC to create the events. Or if you already have a system with an aggregate simply read those events and re-build something more suited to what you really want to query.
DbSet
is already Repository,DbContext
is already UoW.IQueryable
from your repositories, effective joins are not possible.