Ошибка при вставке / обновлении записей в ядре asp.net - PullRequest
0 голосов
/ 10 октября 2018

Когда я пытаюсь вставить / обновить записи, я получаю следующую ошибку:

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

Ниже приведен мой код для того же.Здесь я создаю / генерирую идентификатор (первичный ключ) с шагом 1. Я получаю сообщение об ошибке при сохранении и обновлении

public bool SaveDataCapDetails(List<TDataCapDetails> lstDataCapDetails)
        {
            bool IsSuccess = false;

            using (var dbContextTransaction = _objContext.Database.BeginTransaction())
            {
                try
                {

                    List<TDataCapDetails> lstDataCapDetailsRecords = null;

                    if (lstDataCapDetails.Where(x => x.Id == 0).Count() > 0)
                    {
                        lstDataCapDetailsRecords = new List<TDataCapDetails>();
                        lstDataCapDetailsRecords.InsertRange(0, lstDataCapDetails);

                        int? id = _objContext.TDataCapDetails.Max(x => (int?)x.Id);
                        id = id == null ? 0 : id;
                        foreach (var item in lstDataCapDetailsRecords.Where(x => x.Id == 0))
                        {
                            id = id + 1;
                            item.Id = (int)id;
                        }
                        _objContext.Entry(lstDataCapDetailsRecords).State = EntityState.Detached;
                        _objContext.AddRange(lstDataCapDetailsRecords);
                        _objContext.SaveChanges();
                    }

                    if (lstDataCapDetails.Where(x => x.Id > 0).Count() > 0)
                    {
                        lstDataCapDetailsRecords = new List<TDataCapDetails>();
                        lstDataCapDetailsRecords = lstDataCapDetails.Where(x => x.Id > 0).ToList();
                        _objContext.UpdateRange(lstDataCapDetailsRecords);
                        _objContext.SaveChanges();
                    }

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

            return IsSuccess;
        }

. Вышеупомянутый метод, который я вызываю на бизнес-уровне, показан ниже

bool success = dal.SaveDataCapDetails(lstDataCapDetails)

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

Любая помощь по этому вопросу приветствуется.

Ответы [ 4 ]

0 голосов
/ 13 октября 2018

Если вы хотите иметь таблицу с Primary-Key, а также с Identity-Incremental, вам нужно создать Table после набора ForeignKey, для этого ForeignKey необходимо установить Identity-Incremental.как:

enter image description here

В связи с этой проблемой ваш код изменится на:

    public bool SaveDataCapDetails(List<TDataCapDetails> lstDataCapDetails)
    {
        bool IsSuccess = false;

        using (var dbContextTransaction = _objContext.Database.BeginTransaction())
        {
            try
            {

                List<TDataCapDetails> lstDataCapDetailsRecords = null;

                if (lstDataCapDetails.Where(x => x.Id == 0).Count() > 0)
                {
                    lstDataCapDetailsRecords = new List<TDataCapDetails>();
                    _objContext.AddRange(lstDataCapDetailsRecords);
                    _objContext.SaveChanges();
                }

                if (lstDataCapDetails.Where(x => x.Id > 0).Count() > 0)
                {
                    lstDataCapDetailsRecords = new List<TDataCapDetails>();
                    lstDataCapDetailsRecords = lstDataCapDetails.Where(x => x.Id > 0).ToList();
                    _objContext.UpdateRange(lstDataCapDetailsRecords);
                    _objContext.SaveChanges();
                }

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

        return IsSuccess;
    }
0 голосов
/ 10 октября 2018

Прежде всего, многие люди пропускают эти проверки, что приводит к исключениям во время выполнения.Поэтому вы всегда должны проверять состояние вашей сущности:

context.YourEntities.Local.Any(e => e.Id == id);

или

context.ChangeTracker.Entries<YourEntity>().Any(e => e.Entity.Id == id);

Чтобы убедиться, что ваша сущность «безопасна в использовании», если вы хотите использовать удобный метод, вы можете использовать это:

/// <summary>
    /// Determines whether the specified entity key is attached is attached.
    /// </summary>
    /// <param name="context">The context.</param>
    /// <param name="key">The key.</param>
    /// <returns>
    ///   <c>true</c> if the specified context is attached; otherwise, <c>false</c>.
    /// </returns>
    internal static bool IsAttached(this ObjectContext context, EntityKey key)
    {
        if (key == null)
        {
            throw new ArgumentNullException("key");
        }

        ObjectStateEntry entry;
        if (context.ObjectStateManager.TryGetObjectStateEntry(key, out entry))
        {
            return (entry.State != EntityState.Detached);
        }
        return false;
    }

, а затем :

if (!_objectContext.IsAttached(entity.EntityKey))
{
   _objectContext.Attach(entity);
}

Это спасет васпроблема переопределения метода SaveChanges(), который не рекомендуется ни в коем случае, кроме случаев, когда это действительно необходимо.

0 голосов
/ 10 октября 2018

Я вижу, что вы используете один и тот же метод для объектов Add и Update, первое, что я предлагаю, - это отдельная задача и сделать разные методы один для Add и другой для Update, если это возможно.

Нас другой стороны, неясно, может ли список записей «lstDataCapDetails» содержать все новые записи или набор новых и существующих записей для обновления, во втором случае ваш код выдаст вам ошибку, поскольку вы можете попытаться назначить Id длясуществующей записи, или вы можете попытаться обновить совершенно новую запись.

Повторяйте ошибку, которую вы можете преодолеть, проверив, отслеживается ли сущность, и отсоедините ее, затем присоедините измененную сущность и обновите ее.

здесь вы можете увидеть модифицированную версию вашего метода:

public bool SaveDataCapDetails(List<TDataCapDetails> lstDataCapDetails)
    {
        bool IsSuccess = false;

        using (var dbContextTransaction = _objContext.Database.BeginTransaction())
        {
            try
            {
                int? id = _objContext.TDataCapDetails.Max(x => (int?)x.Id);
                id = id == null ? 0 : id;

                // entities with Id == 0 --> new entities
                // you may need to check if Id == null as well (depends on your data model)
                var entitiesToAdd = lstDataCapDetails.Where(x => x.Id == 0);
                foreach(var entity in entitiesToAdd)
                {
                    entity.Id = id++;

                    // new entities is not tracked, its state can be changed to Added
                    _objContext.Entry(entity).State = EntityState.Added;
                }

                // entities with Id > 0 is already exists in db and needs to be updated
                var entitiesToUpdate = lstDataCapDetails.Where(x => x.Id > 0);
                foreach (var entity in entitiesToUpdate)
                {
                    // check if entity is being tracked
                    var local = _objContext.Set<TDataCapDetails>().Local.FirstOrDefault(x => x.Id.Equals(entity.Id));

                    // if entity is tracked detach it from context
                    if (local != null)
                        _objContext.Entry<TDataCapDetails>(local).State = EntityState.Detached;

                    // attach modified entity and change its state to modified
                    _objContext.Attach(entity).State = EntityState.Modified;
                }

                // optional: assign value for IsSuccess
                IsSuccess = _objContext.SaveChanges() > 0;                    

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

        return IsSuccess;
    }
0 голосов
/ 10 октября 2018

Эта ошибка возникает, когда вы хотите отследить изменения, внесенные в model, а не оставить без изменений model в memory.У меня есть небольшое предложение или на самом деле альтернативный подход предложения, который решит вашу проблему.

EntityFramework будет автоматически отслеживать изменения.Но вы можете Ovverride SaveChanges() в вашем DbContext.

public override int SaveChanges()
{
    foreach (var ent in ChangeTracker.Entries<Client>())
    {
        if (ent.State == EntityState.Modified)
        {
            // Get the changed values
            var modifiedProps = ObjectStateManager.GetObjectStateEntry(ent.EntityKey).GetModifiedProperties();
            var currentValues = ObjectStateManager.GetObjectStateEntry(ent.EntityKey).CurrentValues;
            foreach (var propName in modifiedProps)
            {
                var newValue = currentValues[propName];
                //log your changes
            }
        }
    }

    return base.SaveChanges();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...