EF核心:如何确保只有一个线程在更新具有异步调用的数据库?

时间:2018-12-27 07:39:55

标签: c# .net entity-framework .net-core ef-core-2.0

我正在使用.net核心EF,并希望确保一次只有一个线程正在执行某个代码块,该代码块具有将数据更新到数据库的逻辑:

public async Task<IActionResult> ApproveEntity([FromBody] Entity[] entities)
    {
        Entity Entity = entities.Where(f => f.isMainEntity == true).First();

        try
        {


            try
            {
                try
                    {
                        if (this.ValidateConcurrencyForWriteBack(Entity))
                        {

                           return this.BadRequest("Concurrency Error : Somebody else has already done this action. Please refresh and try again.");
                        }
                        else
                        {
                            try
                            {
                                if (Entity.SupportingDocuments?.Count > 0)
                                {
                                    await this.UploadDocumentsToBlob(Entity, user);
                                    this.Uow.Commit();
                                }
                            }
                            catch (Exception ex)
                            {                                    
                                throw;
                            }

                            await this.BulkChallengeApproveReject(entities, user);
                        }
                    }                     


            }
            catch (DbUpdateConcurrencyException ex)
            {

            }
        }
        catch (Exception ex)
        {

        }

        return this.Ok(Entity);
    }

我希望上面的代码块一次只能由一个线程执行。

  

我尝试使用 Mutext SemaphoreSlim ,但没有获得预期的结果。

validateConcurrency方法将检查记录是否已更新。但这并不能防止线程阻塞。

1 个答案:

答案 0 :(得分:0)

提出该问题的技术解决方案。它不假装是正确的体系结构。

如果您有多个await调用,则不能确定所有这些调用都将在同一线程上执行。这些是异步模式的原理。如果要在同一(而不是在单个)线程上调用inner方法,则必须摆脱内部await的调用,使适当的方法同步(不要进行同步包装,因为它可能导致到死锁Should I expose synchronous wrappers for asynchronous methods?),只在顶层保留一个await

public async Task<IActionResult> ApproveEntity([FromBody] Entity[] entities)
{
    return await Task.Run<IActionResult>(() =>
    {
        try
        {
            //Do synchronisation if needed here.

            try
            {
                try
                {
                    if (this.ValidateConcurrencyForWriteBack(Entity))
                    {

                        return this.BadRequest("Concurrency Error : Somebody else has already done this action. Please refresh and try again.");
                    }
                    else
                    {
                        try
                        {
                            if (Entity.SupportingDocuments?.Count > 0)
                            {
                                this.UploadDocumentsToBlob(Entity, user);//Change method to be synchronous.
                                this.Uow.Commit();
                            }
                        }
                        catch (Exception ex)
                        {
                            throw;
                        }

                        this.BulkChallengeApproveReject(entities, user);//Change method to be synchronous.
                    }
                }
    }
            catch (DbUpdateConcurrencyException ex)
            {

            }
        }
        catch (Exception ex)
        {

        }

        return this.Ok(Entity)
    });
}