避免重复插入数据库

时间:2019-04-02 23:11:16

标签: c# sql-server entity-framework

我有以下代码,将具有随机生成的值“ hawb”的实体作为列之一插入。我的想法是,由于 hawb 是表中的 unique 列,因此,在插入重复值时,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进行了硬编码,因此它会在第一次出现时捕获“重复键异常”。但是,当hawb是随机生成的,并且我确定值不同时,它仍然捕获相同的“ Duplicate Key Exception”。谁能告诉我发生了什么事以及如何实现我的目标?谢谢!

3 个答案:

答案 0 :(得分:3)

您看到的问题是因为您尝试插入一个具有重复ID的实体,但该实体失败了。重试时,您正在创建第二个实体并尝试插入该实体。第一个实体仍与上下文关联,并且仍将尝试保存。您需要先将其与上下文分离,然后再保存新替换或更新现有实体。 (如下)

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 :(得分:1)

其1行额外的代码来检查实体是否存在。首先,不要依靠错误处理来完成工作:

if ( _repository.HAWBAssets.FirstOrDefault(i => i.HAWB == hawb)== null)
    {
     _repository.Insert(entity);
        uniqueHawb = true;
    }

答案 2 :(得分:1)

也许您可以使用纳秒级的距离来缩短记录之间的距离,以减少重复的可能性

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

DateTime.Ticks分辨率为100纳秒