I am trying to implement a caching pattern which may need to utilise Redis. The problem with this pattern is that I need to disable Configuration.ProxyCreationEnabled and then re-enable it afterwards to avoid any issues across a web farm.
What I would like to do is access the DbContext from the IQueryable so I can do this once instead of everywhere. The easiest way to do this is to pass the DbContext being used into my caching extension, however I came across this post:
Access DataContext behind IQueryable
Is there a way of accessing the DbContext in a similar manner to the link above using EF 4.1 Code Fist (DbSet's, etc)?
I have tried to find this myself but have struggled to find the base class from the referenced DbSet in the IQueryable using reflection.
The solution mentioned in Access DataContext behind IQueryable is a hack and should not be used. It relies on the name of a private member variable in the class implementing IQueryable. This means that the implementing class could change in a future release of EF/.NET Framework and break your code. Since the DbContext is not accessible through the IQueryable interface, you should pass it into your caching extension to avoid making assumptions about the IQueryable implementation. Doing so will also more clearly establish the dependency on the DbContext in your caching interface, instead of burying it in the implementation.
Related
Some of you may be familiar with the DbContextScope library, which allows you to nest scopes within your code, and allow those scopes to share a common DbContext. The idea is that the DbContext gets managed for you by the scope library, and instead of calling SaveChanges() on the context, you call SaveChanges() on the scope. The magic happens because the scope will only save all the changes on the context at it's outer-most call of SaveChanges(), so all the nested operations performed on the DbContext get saved in a single transaction at the outer scope-level.
Now that DI is a first-class citizen in .NET Core, it appears that scopes have also become an important part of the .NET Core ecosystem, and the EF Core team, knowing this, has implemented scoping based on allowing DbContexts being injected by the DI system, and (I assume) allowing change saving to happen at scope-levels and not directly on the DbContexts in some way.
So my question are these:
What is the appropriate way to share a DbContext via a scope, allowing the SaveChanges() be managed at the scope level and not the code-level that typically calls SaveChanges() on the DbContext?
Are there new mechanisms in EF Core that manage this for you, just like DbContextScope did this for you as a 3rd party library?
Save me the drama, and spare me the lectures on why you think UOW needs to be implemented in addition to EF. K thnxs bye.
UPDATE: As of 6/2020 there are several forks of DbContextScope that work with EF Core 3.
UPDATE: Forks of this project can be viewed here: https://github.com/mehdime/DbContextScope/network
There are several EF Core 3 versions... I haven't tried any yet, but there you go.
Since Entity Framework 5.0.0, there is IDbContextFactory<TDbContext> that lets you control the creation and disposal (!!) of your DbContexts.
Instead of registering your DbContext with AddDbContext or AddDbContextPool, you can now use AddDbContextFactory or AddPooledDbContextFactory, respectively.
Note that this feature takes care of one of the problems that DbContextScope solves, not all of them. As for what the other problems and solutions are, refer to Mehdi's original post. It is long but excellent.
DbContext sharing is built-in to the Dependency Injection design for EF.
The DI container will generate a scoped DbContext instance for each web request. You can share the DbContext instance from any component that has a dependency on it, and call SaveChanges(), or manage transactions in your outer controller.
I'm working on an ASP.net Web API application with Autofac and Entity Framework.
I've been breaking apart different my service classes into smaller classes in order to make my code more testable and to make my code more SOLID.
I'm using Autofac to inject Entity Framework DbContext into my various helper classes. This becomes problematic because if I use entities queried from DbContext in two different helper classes, I get an error when Entity Framework tries to produce a query.
The error says that Entity Framework cannot produce a query with entities from two different instances of DbContext.
Clearly, the solution is that I need to configure Autofac so that the same instance of DbContext is injected into each of the helper classes, but I'm afraid that if I try to do this, I may get concurrency issues when this application gets deployed to a production environment and many people use it at once.
How do I configure Autofac so that when a request hits my application, my API helper classes all get the same instance of DbContext, but I don't have concurrency issues across multiple requests?
An alternative to the action filter recommended by the Autofac documentation (https://autofaccn.readthedocs.io/en/latest/faq/per-request-scope.html#no-per-request-filter-dependencies-in-web-api) see: "No Per-Request Filter Dependencies in Web API" and manually going to the DependencyResolver for others:
You could have a look at the Medhime DbContextScope unit of work provider. (https://www.nuget.org/packages/EntityFramework.DbContextScope/) compiled for both EF6 and EF Core.
The injected dependencies for your classes becomes a DbContextScopeFactory for the top level, and an AmbientDbContextLocator for your services. These don't "break" with Web API's limitation on the request lifetime scope. The ContextScopeFactory would be initialized once and supply the DbContext, while the locators will be fed that single instance.
It may be worth having a look at if managing context references across services and an API action prove clunky.
How does one share the datacontext of Entity Framework 6.1.1. and inject dependencies (I use Ninject ) like repositories, since EF6 supports repositories and UoW out of the box?
All I can find are SO question and blogpost/articles at least 3 years old. But nothing about EF6, and the current situation which is repositories and UoW being supported out of the box.
The solution contains 2 projects, one is the web project (asp.net-mvc), the other one is the class library acting as the datalayer. The datalayer is based on Code First.
I did create repositories, but didn't realize it was already supported out of the box.
I installed ninject.mvc5 and this is what I registered:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ApplicationDbContext>().ToSelf().InRequestScope();
kernel.Bind<IOrderRepository>().To<OrderRepository>().InRequestScope();
kernel.Bind<IUserRepository>().To<UserRepository>().InRequestScope();
}
So I guess I need to re-factor my code and remove the repositories. But I don't know what should replace them?
Repositories are your DbSets inside the DbContext. The DbContext is your UoW.
Whenever the UoW was used before, you use DbContext now. And you no longer pass individual repositories around, you pass the whole DbContext (it was, frankly, unusual habit before to pass individual repositories, although many people did that).
This now is sufficient then
kernel.Bind<ApplicationDbContext>().ToSelf().InRequestScope();
The ApplicationDbContext is then injected via constructor injection to upper layer classes where applicable.
I used the EF 5.x DbContext Fluent Generator to generate my POCO classes but my properties are not coded as virtual. Don't you have to have that for tracking to occur? Why wouldn't the template already use virtual for properties?
Because we found that for the majority of users it was better to use snapshot change tracking rather than change tracking proxies. Change tracking proxies have their place in certain situations, but usually they add complexity without any real benefit. For more info see http://blog.oneunicorn.com/2011/11/24/why-are-the-dbcontext-t4-templates-so-different-from-the-ef4-poco-templates/ and http://blog.oneunicorn.com/2011/12/05/should-you-use-entity-framework-change-tracking-proxies/
I am playing around with Entity Framework to see how it can be used in a new project I am working on. I put my edmx file in a class library so the Entities (and database access) can be used in multiple places. Currently I have a web project and a console project both referencing the class library.
One of my Entities has a Partial class defined with a static method. The purpose of the method is to accept some parameters and create one or more instances of the specific class. My first version of the method created an ObjectContext instance, created the Entity class (or classes), and returned the Entities to the calling method. The calling method then updated some properties and tried to save the Entities using a new ObjectContext instance. Obviously this did not work because the Entities were bound (correct term ??) to the Context created within the static method.
After some research, I modified the static method to also accept an ObjectContext reference to ensure that all the Entities where created and then later on manipulated and saved using the same Context. This works fine but the design just feels wrong.
Assuming that my one static method may grow into many more, or that my app (especially the web app) would probably benefit from additional layers (DAL or even a Service Layer), does it make sense for all these classes to require an ObjectContext parameter?
I have read on many postings that creating an ObjectContext via a Singleton pattern is a bad idea because "many clients would use the same object". My problem with that is I do not see how that is possible. In a local console app there is only a single user running the app. In a web app there would only be a single user on each request. Where is the user sharing problem? Not a single article/posting mentioned it...but where they referring to a Singleton pattern storing the object instance in the Application context?
I have also seen postings focused on web usage and storing the object instance in the users Session object via the HttpContext object. This makes sense but does not seem to address non-web usage.
I think that whatever solution is appropriate (static methodm, Factory object, etc.) would most likely be implemented in my class library so obviously it needs to support both web and non-web solutions. Maybe check for HttpContext to determine what environment it is running in.
I was hoping http://www.west-wind.com/weblog/posts/2008/Feb/05/Linq-to-SQL-DataContext-Lifetime-Management would be informative but I am having a hard time wrapping my head around the post and the example code seems like overkill for instantiating and sharing a simple object. (Although I am sure I am just not getting it...)
Any thoughts are appreciated.
Thanks.
The issue is not that “many clients would use the same object.” The issue is that the ObjectContext is intended to be a single unit of work. If you use it for many different units of work, you will find that there are a number of problems.
Memory usage will grow and grow.
Your application will become slower as object fixup has to do increasing amounts of work.
Multithreading won't work
The solution is to use the ObjectContext in the manner it is intended, namely, as a single unit of work.