EF Core «еще один экземпляр уже отслеживается» - PullRequest
3 голосов
/ 21 мая 2019

У меня проблема с обновлением объекта в .Net Core 2.2.0 с использованием EF Core 2.2.3.

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

Вот так регистрируется контекст БД:

services.AddDbContext (options =>

options.UseSqlServer(Configuration.GetConnectionString("DbConnection")), ServiceLifetime.Scoped);

Время жизни Scopedустановлен по умолчанию, но я написал, чтобы его было легче понять.

Объект Anomaly получается так:

public IQueryable<Anomaly> GetAll()
    {return _context.Anomalies.Include(a => a.Asset).Include(a => a.Level)
}

public async Task<Anomaly> GetAnomaly(int anomalyId, User user)
{
    var anomaly = await GetAll()
        .FirstOrDefaultAsync(a => a.Id == anomalyId);

    return anomaly;
}

И метод Update() выглядиткак это:

using (var transaction = _context.Database.BeginTransaction())
{
    try
    {
        _context.Anomalies.Update(anomaly);
        _context.SaveChanges();

        transaction.Commit();
    }
    catch (Exception ex)
    {
        transaction.Rollback();
        throw;
    }
}

Он содержит некоторые проверки перед этой транзакцией, но ни один не достаточно уместен в этом контексте.

Здесь я получаю ошибку с экземпляр уже отслеживается . Я не могу понять, как это происходит .. Если контекст Scoped, то

... "будет создан новый экземпляр службыдля каждой области », в данном случае для каждого запроса

Если мой контекст в запросе PUT отличается от контекста запроса GET, как сущность уже отслеживается? Как это работает?на самых основных уровнях?

Единственный способ заставить его работать, это установить состояние для всехl записей от ChangeTracker до EntityState.Detached.Тогда это работает .. но это не имеет смысла, по крайней мере, насколько мне известно ..

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


ОБНОВЛЕНИЕ Вот ссылка на битбакет с примером, воссоздающим эту проблему: Пример обновления ядра EF

Я сериализовал объекты, извлеченные из контекста.

С отслеживанием по левому краю <====> Без отслеживания по правому image With NO tracking on the RIGHT">

1 Ответ

1 голос
/ 21 мая 2019

По умолчанию, когда вы извлекаете объекты, они отслеживаются, и, поскольку они отслеживаются, вы можете просто вызвать SaveChanges, а не вызывать Update. Вы также можете извлекать объекты, не отслеживая их, используя .AsNoTracking ()

вызов Update требуется, если он еще не отслежен, поэтому, если вы используете AsNoTracking, вам нужно использовать Update до SaveChanges

public IQueryable<Anomaly> GetAll()
{    return _context.Anomalies
    .Include(a => a.Asset)
    .Include(a => a.Level);
}

public async Task<Anomaly> GetAnomaly(int anomalyId, User user)
{
    var anomaly = await GetAll()
        .AsNoTracking()
        .FirstOrDefaultAsync(a => a.Id == anomalyId);

    return anomaly;
}

Вы также можете проверить, отслеживается ли объект, чтобы узнать, вызывать ли Update или нет:

using (var transaction = _context.Database.BeginTransaction())
{
    try
    {

        bool tracking = _context.ChangeTracker.Entries<Anomaly>().Any(x => x.Entity.Id == anomaly.Id);
        if (!tracking)
        {
            _context.Anomalies.Update(anomaly);
        }

        _context.SaveChanges();

        transaction.Commit();
    }
    catch (Exception ex)
    {
        transaction.Rollback();
        throw;
    }
}
...