Quantcast
Channel: Active questions tagged blazor - Stack Overflow
Viewing all articles
Browse latest Browse all 4839

Blazor Cross-Service DBContext modifications

$
0
0

I have been trying out Blazor SSR for a bit and I am quite happy with it.

I am now at the point of creating a core for the application. In the architecture that I am targeting I want each Entity to have their own Service (ex: CarService, MakeService, ...). Some of these services perform complex operations and then store/modify/add an entity. The reason for each entity having its own service is seperation of concerns and DRY, I don't want to have repeated code in other services that in addition should not have to know about business specifics of another service.

I want to achieve the following properties with the architecture:

  1. I want to be able to create user interface where a user makes many changes, to potentially different types of entities - through my Entity Services - and the view simply has to call a single SaveChangesAsync on the DBContext. Such as when the user actively clicks the Save Button on the page.
  2. I want to be able to call different entity services in another service and flush all changes at the end via a single SaveChangesAsync on the DBContext or defer that flush to the view.

Considering the following service definition:

public abstract class OrderService<TEntity> : ILXEntityService<TEntity> where TEntity : class{    private LXDBContext _dbContext;    private AnalysisService _analysisService;    public LXModelService(LXDBContext dbContext, AnalysisService analysisService)    {        this._dbContext = dbContext; // <-- Dependency Injection        this._analysisService = analysisService;    }    // ...    public async Task Deactivate(Order order) {        // For simplicity without transaction in this example        foreach (Analysis analysis in order.analyses) {            await _analysisService.Deactivate(analysis); // <-- Calling another service        }        order.activefl = false;    }    // ...}

I want to be able to do this:

@inject LXDBContext dbContext@inject AnalysisService analysisService<button @onclick="OnDeactivate()">Deactivate</button><button @onclick="OnSave()">Save</button>@code {   public async Task OnDeactivate() {       await analysisService.Deactivate(lorder); // <-- Modification   }   public async Task OnSave() {       await dbContext.SaveChangesAsync(); // <-- Saving   }}

Problem is, although this works when using a Scoped DBContext, Scoped DBContexts themselves lead to many problems such as the notorious

a second operation was started on this context instance before aprevious operation completed. this is usually caused by differentthreads concurrently using the same instance of DBContext

This seems unavoidable in Blazor where you have multiple components that hold the same (scoped) DBContext instance.

So the other solution is to use a transiant DBContext, or the per-operation dbcontext (which is the officially recommend way to use DBContext by microsoft). But using a transient or per-operation DBContext takes away all the benefits of using EF Core. Such as lazy-loading, Change Tracking, First-Level Cache, Unit of Work... At that point EF Core just becomes an ORM.

As mentioned transient DBContexts loose change tracking, which is a must have for the application we are building and size of our entities, where its not acceptable that EF Core tries to overwrite each property upon a save - including unmodified ones.

Since I am pretty new to Blazor, I figured people that have experience with working with Blazor and EF Core have a solution for this problem, but searching online did not provide me with any fruitful hints.


Viewing all articles
Browse latest Browse all 4839

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>