C# 实体框架下的并发编辑

C# 实体框架下的并发编辑,c#,sql-server,entity-framework,C#,Sql Server,Entity Framework,我已经实现了一个用于并发实体编辑的锁定实体方法(用户在锁定它之前不能开始编辑)。有关锁定实体的信息存储在表中 下面是实现锁定的代码 public virtual ObjectLockInfo Lock(int id) { using (var context = DataContextFactory.GetContext()) { var i = context.Object

我已经实现了一个用于并发实体编辑的锁定实体方法(用户在锁定它之前不能开始编辑)。有关锁定实体的信息存储在表中

下面是实现锁定的代码

public virtual ObjectLockInfo Lock(int id)
{
        using (var context = DataContextFactory.GetContext())
        {                
             var i =
                context.ObjectLock.Any(
                    c =>
                        c.ObjectID == id && (c.ObjectType == (int) _lockObjectType) &&
                        c.LockExpireDate > DateTime.Now);

            if (i)
                return new ObjectLockInfo
                {
                    ErrorMessage = "Object is locked",
                    IsLocked = false
                };

            var lockLock = new ObjectLock
            {
                LockExpireDate = DateTime.Now.AddMinutes(20),
                LockObjectDate = DateTime.Now,
                ObjectID = id,
                ObjectType = (int) _lockObjectType,
                UserID = _currentUserID
            };

            context.ObjectLock.Add(lockLock);
            context.SaveChanges();
            return new ObjectLockInfo
            {
                Id = lockLock.ID,
                IsLocked = true,
                LockDate = lockLock.LockObjectDate,
                LockExpireDate = lockLock.LockExpireDate
            };
        }

    }
这段代码有一个问题:如果我们在执行
context.SaveChanges()
之前收到另一个锁请求(并且它通过了
Any
条件),我们将在表上获得两个锁

如何避免它(不使用
而不是INSERT
触发器)

使用具有的事务,这将防止您所关心的“幻影行”

public virtual ObjectLockInfo Lock(int id)
{
    using (var context = DataContextFactory.GetContext())
    using (var dbContextTransaction = context.Database.BeginTransaction(IsolationLevel.Serializable)) 
    {                
         var i =
            context.ObjectLock.Any(
                c =>
                    c.ObjectID == id && (c.ObjectType == (int) _lockObjectType) &&
                    c.LockExpireDate > DateTime.Now);

        if (i)
            return new ObjectLockInfo
            {
                ErrorMessage = "Object is locked",
                IsLocked = false
            };

        var lockLock = new ObjectLock
        {
            LockExpireDate = DateTime.Now.AddMinutes(20),
            LockObjectDate = DateTime.Now,
            ObjectID = id,
            ObjectType = (int) _lockObjectType,
            UserID = _currentUserID
        };

        context.ObjectLock.Add(lockLock);
        context.SaveChanges();

        dbContextTransaction.Commit();

        return new ObjectLockInfo
        {
            Id = lockLock.ID,
            IsLocked = true,
            LockDate = lockLock.LockObjectDate,
            LockExpireDate = lockLock.LockExpireDate
        };
    }

}
现在,一旦执行了
Any
,在您提交更改之前,其他写入程序将无法写入表中(如果自己的事务是
read committed
或更高版本,则读卡器将从表中读取)