其他分享
首页 > 其他分享> > CodeGo.net>当行可能不存在时,如何原子递增?

CodeGo.net>当行可能不存在时,如何原子递增?

作者:互联网

假设我有一个DbSet< Item>派生自DbContext的MyContext.项,其中项定义如下.

public class Item
{
    [Key]
    public string Key { get; set; }

    [ConcurrencyCheck]
    public int Value { get; set; }
}

给定一个键,我想以原子方式递增相应的值,其中表中尚未存在的键的隐式值为0.也就是说,以原子方式递增表中不存在的键的结果为1.我目前的做法:

public static async Task IncrementAsync(string key)
{
    using (var context = new MyContext())
    {
        while (true)
        {
            var item = await context.Items.FindAsync(key);
            if (item == null)
            {
                context.Items.Add(new Item { Key = key, Value = 1 });
            }
            else
            {
                item.Value++;
            }
            try
            {
                await context.SaveChangesAsync();
                break;
            }
            catch (DbUpdateException)
            {
                continue;
            }
        }
    }
}

当对IncrementAsync的许多调用同时运行时,此操作将因实时锁定而失败.

>正确的方法是什么?
> while循环是否应该在使用范围之外,以便每次尝试都获得一个新的上下文?我尝试了一下,它使一切正常,但是我觉得创建和破坏这么多上下文的效率很低.
>我是否缺少有关上下文跟踪更改方式的信息?

我的实体框架经验基本上只用于查询,因此,如果您能解释这段代码中我做错的更好的细节,我将非常感谢.

编辑
因为选择的答案没有明确,所以将正确的代码放在这里.请注意,在DbUpdateException之后如何从不重用上下文.

public static async Task IncrementAsync(string key)
{
    while (true)
    {
        using (var context = new MyContext())
        {
            var item = await context.Items.FindAsync(key);
            if (item == null)
            {
                context.Items.Add(new Item { Key = key, Value = 1 });
            }
            else
            {
                item.Value++;
            }
            try
            {
                await context.SaveChangesAsync();
                break;
            }
            catch (DbUpdateException)
            {
                continue;
            }
        }
    }
}

解决方法:

您需要不尝试之间共享上下文.如果根本不对具有DbUpdateException的上下文执行任何操作,就好像您没有明确清理该上下文一样,它可能永远不会返回正常状态.

我希望外部环境会引起问题.如果根据时间发生对单个键的并发调用,则可能会创建错误的上下文设置(由于错误处理程序,该上下文设置会不断被忽略.

除非我误会了数据库中存在密钥的事实,否则不会删除“要添加”的版本.您最终将遇到以下情况之一:

Add "1", 2

要么

Add "1", 1
Update "1", 2

取决于您的第二次迭代是捕获第一次迭代的对象还是新的对象.

这些都不成功,因此您会遇到连续错误.

标签:entity-framework-6,c,net,entity-framework
来源: https://codeday.me/bug/20191120/2042929.html