In our web applications, data from different tables in our database is very often needed. Today you can find 5 or 6 database queries that are executed sequentially for a single query. None of these queries depend on data from the other, so they are ideal candidates for parallel execution. The problem is the well-known DbConcurrencyException , which is DbConcurrencyException when multiple requests are executed in the same context.
Usually we use one context for each request, and then we have a repository class so that we can reuse the requests in different projects. Then we remove the context at the end of the request when the controller is located.
Below is an example that uses parallelism, but there is still a problem!
var fileTask = new Repository().GetFile(id); var filesTask = new Repository().GetAllFiles(); var productsTask = AllProducts(); var versionsTask = new Repository().GetVersions(); var termsTask = new Repository().GetTerms(); await Task.WhenAll(fileTask, filesTask, productsTask, versionsTask, termsTask);
Each repository internally creates its own context, but, as now, they are not deleted. This is problem. I know that I could call Dispose in every repository I create, but this starts to quickly clutter up the code. I could create a wrapper function for each request that uses its own context, but this seems messy and is not a great long-term solution to the problem.
What would be the best way to solve this problem? I would like the client / consumer not to worry about disposing of each repository / context in case of multiple requests being executed in parallel.
The only idea I have now is to follow an approach similar to the factory pattern, except that my factory will keep track of all the objects it creates. Then I could get rid of the factory as soon as I find out that my requests are complete and the factory can internally delete every repository / context.
I am surprised to see such a small discussion around parallelism and Entity Framework, so I hope some more ideas from the community come.
Edit
Here is a simple example of what our repository looks like:
public class Repository : IDisposable { public Repository() { this.context = new Context(); this.context.Configuration.LazyLoadingEnabled = false; } public async Task<File> GetFile(int id) { return await this.context.Files.FirstOrDefaultAsync(f => f.Id == id); } private bool disposed = false; protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { context.Dispose(); } } this.disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } }
As you can see, each repository gets its own context. This means that every repository needs to be disposed of. In the above example, this means that I will need 4 calls to Dispose() .
My thoughts for the factory approach to the problem were something like this:
public class RepositoryFactory : IDisposable { private List<IRepository> repositories; public RepositoryFactory() { this.repositories = new List<IRepository>(); } public IRepository CreateRepository() { var repo = new Repository(); this.repositories.Add(repo); return repo; } #region Dispose private bool disposed = false; protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { foreach (var repo in repositories) { repo.Dispose(); } } } this.disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion }
This factory will be responsible for instantiating my repository, but it will also keep track of all the instances it created. Once this single factory class is removed, it will be internally responsible for deleting each repository created.