skip to Main Content

Using the code you posted in your new answer. But same error when I add a file and the method UpdateVergadering is called.

vergaderingRepository:

private readonly IDbContextFactory<ApplicationDbContext> _factory;

public VergaderingRepository(IDbContextFactory<ApplicationDbContext> dbContextFactory, IDbContextFactory<ApplicationDbContext> factory)
{
    _factory = factory;
}

public async ValueTask<int> UpdateVergadering(Vergadering vergadering)
{
    using var dbContext = _factory.CreateDbContext();
    dbContext.Set<Vergadering>().Update(vergadering);
    return await dbContext.SaveChangesAsync();
}

public async ValueTask<Vergadering> GetVergaderingVoorLiveNotulenAsync (int vergaderingId)
{
    using var dbContext = _factory.CreateDbContext();
            dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
    return await dbContext.Set<Vergadering>().SingleOrDefaultAsync(x => x.Id == vergaderingId);
}

The error I get:

System.InvalidOperationException: ‘The instance of entity type ‘Bestuurslid’ cannot be tracked because another instance with the same key value for {‘Id’} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

2

Answers


  1. You code never completes the component render, you loop within OnInitialized. You also confuse OnInitialized and OnInitializedAsync.

    Here’s a demo page that shows how to use the System.Timers.Timer with an event handler hooked up to the timer to handle the data get and UI update. OnInitializedAsync does the initial data get, sets up the timer, wires up the event handler and completes.

    @page "/"
    @implements IDisposable
    <PageTitle>Index</PageTitle>
    
    <h1>Hello, world!</h1>
    
    Welcome to your new app.
    
    <div class="alert alert-success">
        @_message
    </div>
    
    @code {
        private string? _message = "Not Set";
        private System.Timers.Timer _timer = new System.Timers.Timer(2000);
    
        protected async override Task OnInitializedAsync()
        {
            // Initial data get
            _message = await GetData();
    
            // set uo the timer and hook up the event handler
            _timer.AutoReset = true;
            _timer.Elapsed += this.OnTimerElapsed;
            _timer.Start();
        }
    
        // Event handler for the timer
        private async void OnTimerElapsed(object? sender, System.Timers.ElapsedEventArgs e)
        {
            _message = await GetData();
            // must call this like this as the timer may be running on a different thread
            await this.InvokeAsync(StateHasChanged);
        }
    
        private async ValueTask<string> GetData()
        {
            // emulate an async call to a Db or API
            await Task.Delay(100);
            return DateTime.Now.ToLongTimeString();
        }
    
        // Dispose of the event handler when the Renderer has finished with the component
        public void Dispose()
            => _timer.Elapsed -= this.OnTimerElapsed;
    }
    

    Update on DbContexts and Async behaviour

    Set up a DbContextFactory:

        services.AddDbContextFactory<MyDbContext>(
            options =>
                options.UseSqlServer(@"Server=(localdb)mssqllocaldb;Database=Test"));
    

    And then use the factory to get Db context instances as you need them.

    public sealed class MeetingBroker
    {
        private readonly IDbContextFactory<MyDbContext> _factory;
    
        public MeetingBroker(IDbContextFactory<MyDbContext> factory)
        {
            _factory = factory;
        }
    
    
    public ValueTask<Vergadering> GetVergaderingByIdAsync(int vergaderingId)
    {
        using var dbContext = _factory.CreateDbContext();
        // if you aren't editing the data then you don't need tracking.  Imporves performance
        dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
    
        return await dbContext.Set<TRecord>().SingleOrDefaultAsync(x => x.Id == vergaderingId));
    }
    

    DbContextFctory Update

    You’ve implemented the factory, but not the "Unit of Work" pattern. You’re implementation uses the same context for all activity within the repository and will cause usage clashes.

    Blazor lives in an async world so you need to code for situations where you have parallel processes running on the same resources.

    Your Repository Pattern should look like this:

    
    private readonly IDbContextFactory<ApplicationDbContext> _factoy;
    
    public VergaderingRepository(IDbContextFactory<ApplicationDbContext> dbContextFactory)
    {
        // assigned the factory not a context
        _factory = dbContextFactory;
    }
    
    public async ValueTask<Vergadering> GetVergaderingVoorLiveNotulenAsync (int vergaderingId)
    {
       // creates a context for each transaction
       using dbContext = dbContextFactory.CreateDbContext();
        return await dbContext.Set<Vergadering>().SingleOrDefaultAsync(x => x.Id == vergaderingId);
    }
    
    Login or Signup to reply.
  2. private readonly IDbContextFactory<ApplicationDbContext> _factory;
    
    public VergaderingRepository(IDbContextFactory<ApplicationDbContext> dbContextFactory, IDbContextFactory<ApplicationDbContext> factory)
      => _factory = factory;
    
    public async ValueTask<Vergadering> GetVergaderingVoorLiveNotulenAsync (int vergaderingId)
    {
        using var dbContext = _factory.CreateDbContext();
        // Turning off tracking as this is only a query.
        dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        return await dbContext.Set<Vergadering>().SingleOrDefaultAsync(x => x.Id == vergaderingId);
    }
    
    public async ValueTask<int> UpdateVergadering(Vergadering vergadering)
    {
        using var dbContext = _factory.CreateDbContext();
        // Tracking is required for updates
        //dbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
        dbContext.Set<Vergadering>().Update(vergadering);
        return await dbContext.SaveChangesAsync();
            }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search