EF Core: Как обеспечить, чтобы только один поток обновлял базу данных с асинхронными вызовами? - PullRequest
0 голосов
/ 27 декабря 2018

Я использую .net core 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 голосов
/ 27 декабря 2018

Просто техническое решение вопроса, как оно было сформулировано.Это не претендует на архитектурную правильность.

Если у вас есть несколько вызовов await, вы не можете быть уверены, что все они будут выполнены в одном потоке.Это принципы асинхронного шаблона.Если вы хотите, чтобы метод inner вызывался в одном и том же (не в одном) потоке, то вам нужно избавиться от внутренних вызовов await, сделать соответствующие методы синхронными (не создавайте синхронную оболочку, потому что это может привести кDead Locks Должен ли я предоставлять синхронные оболочки для асинхронных методов? ) и оставить только один 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)
    });
}
...