Избегайте дублирования вставки в базу данных - PullRequest
0 голосов
/ 03 апреля 2019

У меня есть следующий код, который вставляет объект со случайным сгенерированным значением "hawb" в качестве одного из столбцов. Моя идея заключалась в том, что, поскольку hawb является столбцом уникального в таблице, блок try-catch будет перехватывать исключение при вставке повторяющегося значения. Рабочий процесс работает нормально, пока я не начну его тестировать и получу странную ошибку.

[Code]
hawb = "0402135505536";
while (!uniqueHawb)  //insert new hawb
{
    //hawb = $"{DateTime.Now:MMddHHmmss}{RandomHelper.GetRandomNumber(0, 999):000}";

    var entity = new HawbAsset { HAWB = hawb, HawbStatus = "Allocated", AllocatedDateTime = DateTime.Now, AllocationReference = reference };

    try
    {
        _repository.Insert(entity);
        uniqueHawb = true;
    }
    catch (Exception e)
    {
        ;
    }
    hawb = $"{DateTime.Now:MMddHHmmss}{RandomHelper.GetRandomNumber(0, 999):000}";
}

[Model]
    public class HawbAsset : BaseEntity
    {
        [Required(AllowEmptyStrings = false)]
        [Index(IsUnique = true)]
        [StringLength(15)]
        public string HAWB { get; set; }

        [Required(AllowEmptyStrings = false)]
        public string HawbStatus { get; set; }

        public DateTime? AllocatedDateTime { get; set; }

        [Required(AllowEmptyStrings = false)]
        public string AllocationReference { get; set; }

        public DateTime? ConfirmedUsageDateTime { get; set; }

        public DateTime? RecycledDateTime { get; set; }

        public string Owner { get; set; }
    }

Я жестко закодировал дублирующее значение 0402135505536, чтобы оно впервые обнаружило «Исключение дублирующегося ключа», что и ожидается. Однако, когда случайный случай был сгенерирован, и я удостоверился, что значение отличается, это все еще ловит то же самое "Исключение Дублирующего ключа". Может кто-нибудь сказать мне, что происходит и как достичь моей цели? Спасибо!

Ответы [ 3 ]

3 голосов
/ 03 апреля 2019

Проблема, с которой вы столкнулись, заключается в том, что вы попытались вставить один объект с повторяющимся идентификатором, и это не удалось. При повторной попытке вы создаете 2-ю сущность и пытаетесь вставить ее. Первая сущность все еще связана с контекстом и все еще будет пытаться сохранить. Вам необходимо отсоединить его от контекста перед сохранением новой замены или обновить существующую сущность. (Ниже)

hawb = "0402135505536";
var entity = new HawbAsset { HAWB = hawb, HawbStatus = "Allocated", AllocatedDateTime = DateTime.Now, AllocationReference = reference };
while (!uniqueHawb)  //insert new hawb
{
    //hawb = $"{DateTime.Now:MMddHHmmss}{RandomHelper.GetRandomNumber(0, 999):000}";

    try
    {
        _repository.Insert(entity);
        uniqueHawb = true;
    }
    catch (Exception e)
    {
        ;
    }
    entity.HAWB = $"{DateTime.Now:MMddHHmmss}{RandomHelper.GetRandomNumber(0, 999):000}";
}

Чтобы отделить сущность, вам нужно использовать context.Entity(entity).State = EntityState.Detached;, который должен был бы работать через границу вашего хранилища.

В идеале было бы лучше проверить уникальность HAWB перед попыткой вставки, но все же обрабатывать исключение для тех очень, очень редких случаев, когда запись сохраняется между проверкой и сохранением:

int retryCount = 0
while (retryCount < 5)
{
  try
  {
    bool isUnique = false;
    string hawb = null;
    while(!isUnique)
    { 
      hawb = generateHawb();
      isUnique = context.HawbAssets.Any(x => x.HAWB == hawb);
    }
    entity.HAWB = hawb; // this hawb should be unique, so set and insert.
    _repository.Insert(entity);
  }
  catch(UpdateException)
  {
  // log that this has happened, check inner exception for duplicate key and retry, though limit retry attempts if there are deeper issues that might lock up the system in a retry loop.
    retryCount++;
  }
}
1 голос
/ 03 апреля 2019

Может быть, вы можете использовать наносекунды, чтобы сделать большое расстояние между записями, чтобы уменьшить вероятность дублирования

entity.HAWB = $"{DateTime.Now.Ticks}";
// 636898603227146583

DateTime.Ticks разрешение составляет 100 наносекунд

1 голос
/ 03 апреля 2019

Это 1 строка дополнительного кода, чтобы проверить, существует ли сущность.Сделайте это сначала и не полагайтесь на обработку ошибок для выполнения работы:

if ( _repository.HAWBAssets.FirstOrDefault(i => i.HAWB == hawb)== null)
    {
     _repository.Insert(entity);
        uniqueHawb = true;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...