I have a windows application, where I am implementing Dependency injection by Autofac. I have a DBContext class which interacts to db for sql operation. I am using EntityFramework. I have scenario that i need to fetch entities separately with data from db based on some primary key from different tables. Then after some business logic again I need to update those entities in db. But here either all fetched db entities should be updated or none. so I am following unit of work pattern for that. But when fetching db entities from repository with using same dbContext instance, it lost other entities from dbContext. I was using AsImplementedInterfaces() (from autofac) to resolve my DbContext instance, which is not working in my scenario. I changed it SingleInstance() then I am able to achieve my requirement. My doubt here, Is SingleInstance() is thread safe for windows application or for above scenario kind of work?
builder.Register(c => new PortalDbContext(connectionString)).As<IPortalDbContext>().AsImplementedInterfaces();
TO
builder.Register(c => new PortalDbContext(connectionString)).As<IPortalDbContext>().SingleInstance();
I have three repository classes, and one business layer (BL), BL calls all repository class one by one to fetch data with same DBContext instance. Then finally it calls one method DBContext.SaveChanges() which should save all entities data in once or no data should be updated if any one failed. It is working with SingleInstance() scope. But not sure if SingleInstance is thread safe or not.
According to autfac the service resolution are thread safe documentation:
All container operations are safe for use between multiple threads.
The only thing to keep in mind is that resolution context objects are single-threaded so you need to avoid component registration as:
builder.Register(c => new MyComponent(c)); //DON'T DO!
but as:
builder.Register(c =>
{
IContext threadSpecificContext = c.Resolve<IComponentContext>(); // access real context.
return new MyComponent(threadSpecificContext);
}
(see that the threadSpecificContext has been resolved, and the "c" context has not been used)
In your case you didn't make use of the "c" context at all, also see this answer.
Related
This question already has answers here:
How to nest transactions in EF Core 6?
(3 answers)
Closed last year.
I am trying to implement the service and repository patterns in my ASP.NET Core 6 based web application (using EF Core), but I think I am doing a few things wrong. In my controllers I inject a service instance which I can then use like this to get, create, update or delete entities:
[HttpPost]
public async Task<IActionResult> CreateProject([FromBody] Project body)
{
int projectId = await this.projectService.CreateProjectAsync(body);
return CreatedAtAction(nameof(GetProject), new { id = projectId }, null);
}
The CreateProjectAsync function then performs validations (if necessary) and calls the corresponding CreateProjectAsync function of the ProjectRepository class. One important thing to note is that the Project class is created by myself and serves as view model, too. It is mapped to the corresponding EF Core type (such as TblProject) in the repository before it is created/updated in the database or after it has been read from the database.
This approach works fine in many cases but I often encounter problems when I need to use transactions. One example would be that in addition to projects, I also have related entities which I want to create at the same time when creating a new project. I only want this operation to be successful when the project and the related entities were both successfully created, which I cannot do without using transactions. However, my services are not able to create a transaction because they are not aware of the EF Core DbContext class, so my only option right now is to create the transactions directly in the repository. Doing this would force me to create everything in the same repository, but every example I've seen so far suggests to not mix up different entities in a single repository.
How is this usually done in similar projects? Is there anything wrong with my architecture which I should consider changing to make my life easier with this project?
Great question! By default, the EF context is registered as a scoped dependency - so one per request. You could create a simple transaction service (registered as a scoped dependency) that would expose transaction handling. This service could be injected into both your repositories and other service layers as need be.
By returning the transaction object when a transaction is begun, you could grant each layer autonomy over committing or rolling back it's own transaction.
You could also add some cleanup logic to the Dispose method of the transaction service to commit or rollback any open transactions when the service is being disposed.
Edit for personal practice:
I have abandoned the repository pattern for several projects except for frequent get operations. Using the EF context directly in service layers allows me to take advantage of navigation properties to perform complex multi-table inserts or edits. I also get the added benefit of a single round trip to the database to execute these operations, as well as implicit transaction wrapping. Personally, it gets more and more difficult to make the case for the repository pattern on EF projects - other than you get really locked in to EF because it is all over the lower service layers.
In my app I have a Mediatr handler which has a DBContext and 2 services injected via DI. Each of these services have their own DBContext also injected via DI.
Is there a way for me to execute all of the work carried out in the handler and services within a single EF Core transaction?
The only way I can think of doing this would be for the handler to new up each service and pass it's instance of the DBContext to each and call SaveChanges at the end of the handler. This would work but I'm wondering if there's a better way where I don't have to instantiate each service myself.
I think you're looking for the Unit Of Work-pattern. In this, you create a Unit of Work object that has a reference to your DbContext. Everywhere, you inject your Unit Of Work instead of your DbContext. Since this is the same object within the same scope, all of your services will use the same DbContext reference as well. A call to SaveChanges() will then affect multiple tables at once as well.
This seems like a good link: https://cpratt.co/repository-and-unit-of-work-patterns-with-entity-framework/
You can do this by making a singleton handler that you inject into the services.
What you want to do is something you must not! First, operations that spread across multiple services tend to take time, meaning you will have your transaction open for a while. Second, if the client breaks and doesn't complete the chain of operations, your transaction will stay open. Third, you will have hard time to cope with concurrent operations.
A better possible approach will be to simulate a transaction by storing your data with a temporary flag, that at the end you clear, or that you use to delete records in case you need to rollback.
In my ASP.NET Core application, I have some complex business logic involving multiple threads doing database operations outside the scope of an HTTP request. Accessing the database from the same thread processing the request is trivial, but when spawning threads that requires their own DbContext, this turns out to be tedious. As the DbContext itself is not thread-safe, I have tried to create a new DbContext together with its options in addition to obtaining a DbContext from an IServiceProvider. With both approaches, I get the following exception:
An attempt was made to use the context while it is being configured. A
DbContext instance cannot be used inside OnConfiguring since it is
still being configured at this point.
I'm getting the impression that I'm approaching this problem the wrong way and that I'm not supposed to handle database connections like this. How am I then supposed to obtain a DbContext in a separate thread from the one processing incoming requests?
I tested and it works:
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
optionsBuilder.UseSqlServer(DbConnectionString);
using (var context = new ApplicationDbContext(optionsBuilder.Options))
{
//save or update() on *context* here
}
It turned out my test code had a small typo making it use the same DbContext across all threads. It is however required that I create a new DbContext instance but I cannot obtain one through the IServiceProvider as mentioned in my question.
I'm using MVC .Net. Usually I always use something like below to create one instance whenever I need to query the DB:
using (EntitiesContext ctx = new EntitiesContext())
{
....
}
Then I see lots of sample codes that always have one instance of DBContext in the controller, use it whenever needed, and Dispose it when the controller is Disposed.
My question is: which one is the right way to use it? Any advantage/disadvantage? Maybe, is there any performance difference?
Thanks
Using a context by controller instance has multiple advantages :
It's scoped to the controller, therefore if you need it multiple times you allocate only one instance
EntityFramework use local caching, then if you query multiple times over the same DbSet with the same parameters, it will match those entities in cache instead of querying the database
If you use the repository pattern, it's a good practice to share your context accross repositories. That way, each repository is able to see what as been done by other repositories if you manipulate multiple repository in the same controller scope
From the Getting Started with ASP.NET 5 and Entity Framework 6 , you can read :
Context should be resolved once per scope to ensure performance and ensure reliable operation of Entity Framework.
See a related SO post that deeply explain why it's better to use this approach.
In my MVC 5 app with EF6 started using interfaces and Ninject and ran into problems.
I call multiple implementations to get a data and when saving it entities are disconnected and have problems with many to many and similar.
So I want to make my DataContext db = new DataContext(); global so I just refer to it, not create new instance in every class.
Where do I declare it and how to call it?
DO NOT DO THAT.
At least because, due to caching, you will finish to have all the database in memory.
Your DbContext MUST have a scope as small as possible. Certainly not an application scope.
"Let the connection pool do his job".
All u need is repository pattern and Unit of work.
there is useful link about implementation
http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application