实体框架:处理新记录的主键唯一值(标识规范关闭)
本文关键字:标识 范关闭 唯一 框架 处理 新记录 实体 | 更新日期: 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;
}
}