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

C# 实体框架:处理新记录的主键唯一值(标识规范已关闭),c#,sql-server,asp.net-mvc,entity-framework,C#,Sql Server,Asp.net Mvc,Entity Framework,首先,我不能修改表的设计以打开主键的标识规范 我的问题是如何在EF中处理用户A和用户B在添加新记录时主键没有冲突的情况 我正在从事Asp.NETMVC5项目 我当前的代码: public void NewFooMember(FooMember fooMember) { fooMember.NullGuard("fooMember"); // This is the primary key fooMember.MemberKey = NextFooMemberKey();

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

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

我正在从事Asp.NETMVC5项目

我当前的代码:

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;
}

您当前的想法存在一个缺陷,即在插入新记录之前,可以同时对
nextfoomberkey
进行两个不同的调用,从而导致使用相同的密钥将两个记录插入数据库

为了解决这个问题,您应该确保该序列是线程安全的,并在密钥生成和插入功能周围添加
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;
  }
}