C# 在transactionScope内删除用户时超时 背景

C# 在transactionScope内删除用户时超时 背景,c#,asp.net-mvc,entity-framework,asp.net-identity,transactionscope,C#,Asp.net Mvc,Entity Framework,Asp.net Identity,Transactionscope,我们正在尝试归档旧的用户数据,以使最常用的表更小 发行 用于删除记录的普通EF代码适用于我们的自定义表。AspNetUsers表是另一种情况。这样做的方法似乎是使用_userManager.Delete或_userManager.deleteAync。这些操作不需要在一个事务中执行多个db调用。当我将其包装在transactionScope中时,它会超时。以下是一个例子: public bool DeleteByMultipleIds(List<string> idsToRemov

我们正在尝试归档旧的用户数据,以使最常用的表更小

  • 发行

    用于删除记录的普通EF代码适用于我们的自定义表。AspNetUsers表是另一种情况。这样做的方法似乎是使用_userManager.Delete或_userManager.deleteAync。这些操作不需要在一个事务中执行多个db调用。当我将其包装在transactionScope中时,它会超时。以下是一个例子:

    public bool DeleteByMultipleIds(List<string> idsToRemove)
    {
        try
        {
            using (var scope = new TransactionScope())
            {
                foreach (var id in idsToRemove)
                {
                    var user = _userManager.FindById(id);
                    //copy user data to archive table
                    _userManager.Delete(user);//causes timeout
                }
                scope.Complete();
            }
            return true;
        }
        catch (TransactionAbortedException e)
        {
            Logger.Publish(e);
            return false;
        }
        catch (Exception e)
        {
            Logger.Publish(e);
            return false;
        }
    }
    

    它也将超时。此SQL在执行C#代码之前工作。因此,似乎超过1 db的命中率会锁定表。如何在一个事务中找到用户(db hit#1)并删除用户(db hit#2)?

    microsoft的建议是在与EF进行事务时使用不同的API。这是由于EF和TransactionScope类之间的交互。隐式地,事务作用域强制事情可序列化,这会导致死锁

    以下是EF内部API的详细说明:

    作为参考,如果用户管理器公开了datacontext并使用(var dbContextTransaction=context.Database.BeginTransaction()){//code}


    或者,看看您的场景,您实际上非常安全地找到了用户ID,然后尝试删除它,如果用户在查找和删除之间的几秒钟内被删除,那么您只需捕获一个错误。

    对于我来说,问题涉及在同一事务中使用多个单独的
    DbContext
    s。
    BeginTransaction()
    方法不起作用

    在内部,
    UserManager.Delete()
    正在调用
    RunSync()包装中的
    async
    方法。因此,为我的
    TransactionScope
    使用
    TransactionScope asyncFlowOption.Enabled
    参数确实有效:

    using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
    {
        _myContext1.Delete(organisation);
        _myContext2.Delete(orders);
        _userManager.Delete(user);
        scope.Complete();
    }
    

    为什么要在阅读过程中处理事务?您没有更改数据,因此没有任何内容可以回滚。同意上面的评论,实际上您可以使用删除范围,这是一种更优化的删除方式。@RichardBarker。谢谢你,说得好。我已尝试在事务外部读取并传入要删除的用户。然后代码抛出“无法删除对象,因为在ObjectStateManager中找不到它。”因为(我认为)读取的上下文与删除的上下文不同。也许我没听清你的建议。@AnshulNigam谢谢你。是的,我可以对多个实体对象使用RemoveRange()。我对其他实体表执行此操作。但是在使用MS asp.net-identity时,我似乎不能(或不应该)为AspNetusers表执行此操作。例如,Horizon_Net的回复。我可能有点误解,但您知道使用MS Identity在users表上执行deleteRange的代码吗?我会按照下面的答案来做。更改您的交易以使用您在该评论中获得的内容。如果成功了,记住接吻的方法。谢谢!当我使用context.Database.BeginTransaction()方法而不是TransactionScope()方法时,它不会出错。链接非常有用!我仍然希望继续使用事务,以便我们也可以在一个事务中删除与这些用户关联的表中的数据。现在它工作了!我想你是新来的:)。您需要单击“向上”按钮,然后单击勾号,表示此答案解决了您的问题。这就是stackoverflow的工作原理。谢谢,出色地解决了我的问题。这应该是公认的答案
    using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
    {
        _myContext1.Delete(organisation);
        _myContext2.Delete(orders);
        _userManager.Delete(user);
        scope.Complete();
    }