Ошибка EF: экземпляр объекта типа «Объект» не может быть отслежен, потому что другой экземпляр

#c# #asp.net-core #.net-core #entity-framework-core #blazor-server-side

#c# #asp.net-core #.net-core #entity-framework-core #blazor-на стороне сервера

Вопрос:

Я сталкиваюсь с потерей с этим и новичком в Blazor и пытаюсь его изучить (.NET 5)

У меня простая модель:

 public class Status
{
    [Key]
    public int Id { get; set; }
    
    [Required]
    public string Name { get; set; }
    public DateTime CreatedOn { get; set; }
    public DateTime LastUpdatedOn { get; set; }
}
 

Startup.cs Я регистрирую свою базу данных и службы.

  services.AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("Default")),(ServiceLifetime.Scoped));

 services.AddAutoMapper(typeof(Startup));
 services.AddScoped<IStatusRepo, StatusRepo>();
 services.AddScoped<IStatusService, StatusService>();
 

Код, лежащий в основе файла моего компонента, приведен ниже. GetStatus Вызов возвращает dto, отличный от того, который принимает метод службы обновления статуса, поэтому я конвертирую его в UpdateStatus метод.

 public partial class EditStatus : ComponentBase
{
        [Parameter]
        public int StatusId { get; set; }

        [Inject]
        IStatusService StatusService { get; set; }

        [Inject]
        NavigationManager navigationManager { get; set; }

        public bool ShowLoadError { get; set; } = false;
        private StatusDetailDto StatusToEdit { get; set; } = new StatusDetailDto();

        protected override async Task OnInitializedAsync()
        {
            await GetStatusToEdit(StatusId);
        }

        public async Task GetStatusToEdit(int statusId)
        {
            try
            {
                StatusToEdit = await StatusService.GetStatusById(statusId);
            }
            catch (Exception ex)
            {
                ShowLoadError = true;
            }
        }

        protected async void UpdateStatus()
        {
            UpdateStatusDto updatedStatus = new UpdateStatusDto();
            updatedStatus.Id = StatusToEdit.Id;
            updatedStatus.Name = StatusToEdit.Name;

            StatusDetailDto statusUpdated = await StatusService.UpdateStatus(updatedStatus);

            if (statusUpdated != null)
            {
                navigationManager.NavigateTo("status/manage");
            }
            else
            {
                Console.WriteLine("No here");
            }
        }
    }
 

Уровень обслуживания:

 public async Task<StatusDetailDto> UpdateStatus(UpdateStatusDto statusDto)
{
    Status statusToUpdate = mapper.Map<UpdateStatusDto, Status>(statusDto);
    Status updatedStatus = await statusRepo.UpdateStatus(statusToUpdate);
    return mapper.Map<Status, StatusDetailDto>(updatedStatus);
}
 

И репозиторий

 public async Task<Status> UpdateStatus(Status Status)
{
   if (Status is null) 
        throw new ArgumentNullException("Nulls are not allowed.");

   try
   {
        Status.LastUpdatedOn = DateTime.Now;

        // THIS LINE THROWS THE ERROR!
        _dbContext.Entry(Status).State = EntityState.Modified; 

        await _dbContext.SaveChangesAsync();
        return Status;
    }
    catch (Exception)
    {
        throw;
    }
}
 

Возможно, мои сроки службы неверны? Я тоже пробовал переходное время жизни для своего dbcontext . Что может вызвать эту ошибку?

Экземпляр объекта типа ‘Status’ не может быть отслежен, поскольку другой экземпляр с тем же значением ключа для {‘Id’} уже отслеживается.

Ответ №1:

Сначала исправьте загрузочный файл, удалив ServiceLifetime.Область действия из AddDbContext

 services.AddDbContext<ApplicationDbContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("Default")));
 

Затем измените код вашего UpdateStatus

 public async Task<Status> UpdateStatus(Status status)
{
   if (status is null) throw new ArgumentNullException("Nulls are not allowed.");
   try
   {
    var existedItem=_dbContext.Set<Status>().FirstOrDefaultAsync(i=i.Id==status.id);
       if(existedItem==null) throw new ArgumentNullException("Item is not found.");
      existedItem.LastUpdatedOn = DateTime.Now;
      _dbContext.Entry(existedItem).State = EntityState.Modified; 
      await _dbContext.SaveChangesAsync();
      return Status;
    }
    catch (Exception)
    {
      throw;
    }
}
 

Комментарии:

1. Зачем мне нужно снова получать товар, если он у меня уже есть в аргументах?

2. Извините, это не работает. Он по-прежнему выдает исключение и пропускает вызов SaveChanges.

3. Но ваш комментарий заставил меня исправить это аналогичным образом, так что спасибо!

4. Это может быть что-то другое. Я немного изменил ваш код, и он работал нормально. Я не пытался быть грубым, ценю ваш ответ.