-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Using Entity Framework Core with Blazor #10448
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
yes, had this problem already and was wondering the same. Current solution for me was to create a new DB Context with the using statement inside every DataAccess method. |
Current solution is to make it |
Agreed. My read is that the first thing we need is a pattern for creating (Note: I am not familiar with Blazor yet, but I am making a few assumptions, like that request scopes still exist, and that in the same application you can mix Blazor with regular "stateless Web" usages) One thing that I believe @davidfowl mentioned to me is that we could register a EDIT: Currently, you can do this by creating an instance with the This would allow you to control the lifetime of each individual |
If we identify a pattern equivalent to associating the lifetime of the context with a "window" that works in 80% of Blazor scenarios and we find a way to automate it, we can do that too. |
BTW, I created dotnet/efcore#4441 more than three years ago to have a I now believe again there is probably value in having the factory registered, but I am curious if anyone thinks the pattern above is sufficient. |
@detachmode @vertonghenb Part of this discussion is to ensure we've identified all of the related issues with using EF Core with Blazor today. To help us out, could you please clarify exactly what issues you hit? |
@danroth27 I went with the using statement over the transient solution, so I could use my data access layer even in Singleton instances, which was a design choice. |
I am using entity framework core but i have a issue, while fill data Value getting but not displaying when i am using include command/ after joining the related table how rectify that . |
Fixes: #5496 Fixes: #10448 This change adds a *utility* base class that encourages you to do the right thing when you need to interact with a disposable scoped or transient service. This solution ties the lifetime of a DI scope and a service to a component instance. Note that this is not recursive - we expect users to pass services like this around (or as cascading values) if the design dictates it.
Fixes: #5496 Fixes: #10448 This change adds a *utility* base class that encourages you to do the right thing when you need to interact with a disposable scoped or transient service. This solution ties the lifetime of a DI scope and a service to a component instance. Note that this is not recursive - we expect users to pass services like this around (or as cascading values) if the design dictates it.
Fixes: #5496 Fixes: #10448 This change adds a *utility* base class that encourages you to do the right thing when you need to interact with a disposable scoped or transient service. This solution ties the lifetime of a DI scope and a service to a component instance. Note that this is not recursive - we expect users to pass services like this around (or as cascading values) if the design dictates it.
My DB Context was disposed when using Blazor:
I am using: services.AddDbContextPool<MyDbContext>(options =>
{
var connectionString = Configuration.GetConnectionString("DB");
options.UseNpgsql(connectionString);
}); I also tried this to no avail:
How do I solve this problem? |
@ryanelian - Check your code that may wrap any usage (meaning queries) of MyDbContext that wraps the code in a "using" statement. The using statement causes the MyDbContext to be disposed of too early. Remove the using statements. Instead, use code like this:
|
Hi thank you for replying. I've just found the bug, it's NOT the It's because my Blazor
EditFormModel Form; // = new EditFormModel(); // initially this was NULL. I thought if I assign a value to it during `protected override async Task OnInitializedAsync()` it would work. Unfortunately it exploded, and for some reason the exception message is the EF Core error message above. (huh) |
For those of you having For this, you'll need to inject |
To tag onto what @JeroMiya said, here's a class that I use to quickly create/dispose a
Usage:
|
As per @danroth27 (first post in this thread), we need a robust pattern for how the EF should be used by Blazor (Server side). There have been multiple post on this thread, and I think we just need a bit of clarification on best practice from Microsoft. The problem (as I see it) is that a Blazor (Server) App is a connected application and the Service (injected into the Page) is therefore long-lived. The page may have a very rich and responsive UI resulting in multiple calls to the Service (c.f multiple AJAX calls from a web page hitting the WebServer) at the same time. If the Service has a long-lived EF Context, then it means that multiple threads may call the Context at the same time, resulting in an InvalidOperationException (only one thread may access the Context at any one time). In an above post, @detachmode said that a long running context caches data, and suggested that this may lead to a problem that users staying on the same page will end up seeing stale data. Is that true though? From the EF6 documentation (not found the equivalent for Core) it states:
My reading of this is that it will still go to the DB to see if the entity is different - if it is different, you'll get the latest version, but if it's the same, you'll get the previous version. Perhaps Microsoft can confirm... If I'm interpreting this correctly then caching is advantageous and so you want a long lived Context (which would also remove the overhead of having to instantiate it every time). If so, then how do you prevent two threads from accessing the Context at any one time? One could use a SemaphoreSlim(1,1) to lock the context allowing just one thread at a time. But if that were the case then wouldn't Microsoft have built that into the EF Core framework? Microsoft, what's the "best practice" for using EF a real-world, rich UI, Blazor-Server app? |
No. The threading has always happened at a higher level. WinForms and WPF have a single UI thread, and things like Forms and ViewModels that you can hang a long-lived DbContext from. ASP.NET has the Request scope, and ASP.NET guarantees that the a request-scoped DbContext is not simultaneously accessed from multiple threads. |
Seems like the preferred pattern for Blazor (Server) therefore looks to be:
|
You can also derive from |
Great feedback. May I suggest that when a Developer chooses to create a new Blazor application in Visual Studio that the template is updated to put the "best practice" code for consuming the Entity Framework, even if it's commented out. This code should be "best practice" for a super-rich UI, not a Hello World app. If things work perfectly out-of-the-box then I think you'll get a higher adoption rate for Blazor. |
Having experimented with both approaches, I'm finding that the following seem to be identical in my app:
c.f.
With both approaches, whenever a component is called, the constructor of both the Context and Service are called. However, I'm never seeing the Dispose() called on the Context nor the Service....thought the framework called this when it went out of scope. Am I right then that this is an "either / or" approach, or is there a requirement to have:
|
About
|
My original approach was to use a
Have a read of this thread for Gustavo Navarro's Blazor.Grid. In this post he proposes controlling the lifetime of the Context (scroll down to his next entry if you want to see what problem he was experiencing). So the context is short-lived and has the scope of each operation (so, truly "transient"). What are the drawbacks to his approach?
|
Yes. But a useful bottleneck. More of a resource policy that each client can only use one database connection at a time. It won't impact the aggregate throughput of your application.
For a rich UI having a single, shared context for the duration of an operation will allow the user to make changes over a number of UI interactions and then call a single SaveChanges() for all the pending changes to be persisted in a single transaction, and with client-side optimistic concurrency. |
What dbrownems says certainly sounds logical: the long-lived Context will be unique to that user (multiple people on the same Page will have different Contexts) so any locks can't affect other users. So Microsoft, is locking the preferred way to go based on Dani Herrera's comments above? As an FYI, this was my implementation (albeit cutdown)
And the in Service
When I was using this, I had in the StartUp.cs
|
@ctrl-alt-d (Dani Herrera) I don't think that |
Since this is a closed issue I don't think anyone is watching this.... |
@sven5 Could you please open a new issue for that and any other threading issues that you're hitting? Thanks! |
We need to consider how EntityFramework Core should be used with Blazor:
@divega @ajcvickers
The text was updated successfully, but these errors were encountered: