StateHasChanged() не обновляет значения базы данных

Используя код, который вы разместили в своем новом ответе. Но та же ошибка, когда я добавляю файл и вызывается метод UpdateVergadering.

vergaderingРепозиторий:

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);
}

Ошибка, которую я получаю:

System.InvalidOperationException: «Экземпляр объекта типа «Bestuurslid» не может быть отслежен, поскольку другой экземпляр с тем же значением ключа для {'Id'} уже отслеживается. При присоединении существующих сущностей убедитесь, что присоединен только один экземпляр сущности с заданным значением ключа.

Не меняйте вопрос, это делает недействительными ответы. Разместите продолжение.

H H 16.02.2023 16:42
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
112
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ваш код никогда не завершает рендеринг компонента, вы зацикливаетесь внутри OnInitialized. Вы тоже путаете OnInitialized и OnInitializedAsync.

Вот демонстрационная страница, которая показывает, как использовать System.Timers.Timer с обработчиком событий, подключенным к таймеру, для обработки получения данных и обновления пользовательского интерфейса. OnInitializedAsync получает исходные данные, устанавливает таймер, подключает обработчик событий и завершает работу.

@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;
}

Обновление DbContexts и асинхронного поведения

Настройте DbContextFactory:

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

А затем используйте фабрику, чтобы получить экземпляры контекста Db по мере необходимости.

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));
}

Обновление ДбКонтекстФтори

Вы реализовали фабрику, но не шаблон "Единица работы". Ваша реализация использует один и тот же контекст для всех действий в репозитории и вызовет конфликты использования.

Blazor живет в асинхронном мире, поэтому вам нужно кодировать для ситуаций, когда у вас есть параллельные процессы, работающие на одних и тех же ресурсах.

Ваш шаблон репозитория должен выглядеть так:


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);
}

@Shaun Я обновил свой вопрос вашим ответом, но он не работает

Jeremy 11.02.2023 12:55

Поставьте точку останова на OnTimerElapsed и проверьте объект Meeting, который вы получаете из GetData. Также что такое vergaderingBL.GetVergaderingById(VergaderingId), вызов API или вызов конвейера данных в БД? Это асинхронно?

MrC aka Shaun Curtis 11.02.2023 13:43

@Shaun Я обновил свой вопрос выше, указав запрошенный вами код.

Jeremy 11.02.2023 14:08

@Shaun Я поставил точку останова на OnTimerElapsed и получил следующее сообщение об ошибке System.InvalidOperationException: 'A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.'

Jeremy 11.02.2023 14:11

См. — learn.microsoft.com/en-us/ef/core/dbcontext-configuration/… . Я обновил свой ответ.

MrC aka Shaun Curtis 11.02.2023 14:43

@Shaun получает ошибку при вызове базы данных System.InvalidOperationException: 'A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext.

Jeremy 12.02.2023 19:08

@Shaun Я обновил свой код в вопросе

Jeremy 12.02.2023 19:30

Вы внедрили DbContextFactory?

MrC aka Shaun Curtis 12.02.2023 19:42

@Шон Да, есть. Я добавил это к своему вопросу.

Jeremy 13.02.2023 08:57

Вы реализовали фабрику, но не шаблон "Единица работы". Ваша реализация использует один и тот же контекст для всех действий в репозитории и вызовет конфликты использования. Blazor живет в асинхронном мире, поэтому вам нужно кодировать параллельные процессы, работающие на одних и тех же ресурсах.

MrC aka Shaun Curtis 13.02.2023 10:08

@Shaun Я обновил свой вопрос (код репозитория). На той же странице, где показано оперативное обновление, вы можете загрузить файл. Таким образом, одновременно с EFC вызывается запрос на обновление. Но я получаю сообщение об ошибке: System.InvalidOperationException: 'The instance of entity type 'Vergadering' 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. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.'

Jeremy 15.02.2023 10:44

@Шон Как это возможно? Я использую NoTracking в методе LiveAsync?

Jeremy 15.02.2023 10:45

ПОСМОТРИТЕ код вашего репозитория. Какие DbContext используют оба метода? Не создавайте контекст уровня класса - _db = dbContextFactory.CreateDbContext();. Точно скопируйте мой GetVergaderingByIdAsync.

MrC aka Shaun Curtis 15.02.2023 13:52

@Shaun Я обновил свой вопрос вашим кодом в моем репозитории. Все та же ошибка

Jeremy 16.02.2023 15:20

Смотрите ответ ниже.

MrC aka Shaun Curtis 16.02.2023 15:38
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();
        }

@Шон, нет, не работает. 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.

Jeremy 16.02.2023 16:18

Итак, что такое Bestuurslid?

MrC aka Shaun Curtis 16.02.2023 16:21

@Shaun Столбец в таблице Vergaderingen. public ICollection<Bestuurslid> Aanwezigen { get; set; }

Jeremy 16.02.2023 16:27

У вас есть проблемы в вашей модели данных EF, которые вам нужно отследить. Я не эксперт по EF.

MrC aka Shaun Curtis 16.02.2023 16:35

Другие вопросы по теме