实体框架:处理新记录的主键唯一值(标识规范关闭)

本文关键字:标识 范关闭 唯一 框架 处理 新记录 实体 | 更新日期: 2023-09-27 17:49:34

首先,我不能修改表的设计来打开主键的标识规范。

我的问题是如何在EF中处理用户A和用户B在添加新记录时主键没有冲突的情况。

我正在研究Asp。Net MVC5项目。

我的当前代码:

public void NewFooMember(FooMember fooMember)
{
    fooMember.NullGuard("fooMember");
    // This is the primary key
    fooMember.MemberKey = NextFooMemberKey();
    Repo.Add(fooMember);
    UnitOfWork.Commit();
}
public int NextFooMemberKey()
{
    int? maxFooMemberKey = Repo.Data.Max(fm => (int?)fm.MemberKey);
    if (!maxFooMemberKey.HasValue)
    {
        return 1;
    }
    return maxFooMemberKey.Value + 1;
}

实体框架:处理新记录的主键唯一值(标识规范关闭)

您当前的想法有两个不同的调用可以同时对NextFooMemberKey进行的缺陷,在插入新记录之前,导致两个记录以相同的键插入到Db中。

为了解决这个问题,您应该确保这个序列是线程安全的,并在键生成和插入功能周围添加lock调用,以确保一次只有一个线程可以运行该代码段(确保唯一的键)。

您还可以对键生成函数进行一些优化—假设您没有处理多个服务器,您可以缓存最后一个键并每次只增加它—这样您就不必每次生成键时都往返于数据库(您需要解决插入失败的情况,在这种情况下您需要减少静态保存的键)。

private object newFooLock = new object();
public void NewFooMember(FooMember fooMember)
{
  fooMember.NullGuard("fooMember");
  lock (newFooLock) {        // now only one thread can get in here at a time
    try 
    {
      fooMember.MemberKey = NextFooMemberKey();
      Repo.Add(fooMember);
      UnitOfWork.Commit();
    }
    catch (Exception ex)
    {
      lastFooKey--;    // decrement saved value
    }
  }
}
private object newFooKeyLock = new object();
private static int? lastFooKey = null;
public int NextFooMemberKey()
{ 
  // also lock the key generation, just to be safe
  lock (newFooKeyLock) { 
    if (lastFooKey == null) 
    {
      // only get from the db if the local value is not yet populated
      lastFooKey = Repo.Data.Max(fm => (int?)fm.MemberKey) ?? 1;
    }
    lastFooKey++;
    return lastFooKey.Value;
  }
}