Preventing race condition of if-exists-update-else-insert in Entity Framework

后端 未结 4 722
天涯浪人
天涯浪人 2020-12-13 00:33

I\'ve been reading other questions on how to implement if-exists-insert-else-update semantics in EF, but either I\'m not understanding how the answers work, or they are in f

4条回答
  •  没有蜡笔的小新
    2020-12-13 01:15

    Just to add my way, not that it really deals with the annoyance of exceptions being thrown and transactions not quite cutting it as a scalable solution but it does avoid race conditions from causing problems where lock type solutions are not possible (easily managed) such as in distributed systems.

    I very simply use the exception and try the insert first. I use a modification of your original code as an example:

    using(var context = new MyEntities())
    {
        EntityEntry entityUser = null;
        try 
        {
            user = new User
            {
                 // etc
            };
            entityUser = context.Users.Add(user);
            context.SaveChanges(); // Will throw if the entity already exists
        } 
        catch (DbUpdateException x)
        when (x.InnerException != null && x.InnerException.Message.StartsWith("Cannot insert duplicate key row in object"))
        {
            if (entityUser != null)
            {
                // Detach the entity to stop it hanging around on the context
                entityUser.State = EntityState.Detached;
            }
            var user = context.Users.Find(userId);
            if (user != null) // just in case someone deleted it in the mean time
            {
                // update the user
                user.property = newProperty;
                context.SaveChanges();
            }
        }
    }
    

    It's not pretty, but it works and might be of use to someone.

提交回复
热议问题