Список синхронных запросов dbcontext, переписанных как асинхронные вызовы в разных контекстах - PullRequest
0 голосов
/ 20 марта 2019

Этот пост в контексте использования Entity Framework версии 6.2.

Хорошо, у меня довольно медленная конечная точка, по сути, следующая:

    public IHttpActionResult GetCounts()
    {
        int count1 = service.GetCount1();
        int count2 = service.GetCount2();

        Models.Counts ret = new Counts()
        {
            Count1 = count1,
            Count2 = count2,
        };

        return Ok(ret);
    }

каждый вызов службы выполняется в одном и том же экземпляре dbcontext:

//In the service
public class Service 
{
    private MyDbContext context;
    public Service() 
    { 
       context = new MyDbContext(); 
    } 

    public int GetCount1()
    { 
       return context.coll1.Count(); 
    }
    public int GetCount2()
    { 
       return context.coll2.Count(); 
    }
}

было бы лучше обработать каждый сервисный вызов как отдельные единицы работы и создать контексты для каждого из них, а затем использовать асинхронные методы EF, как показано ниже:

public async Task<IHttpActionResult> GetCountsAsync()
    {
        var tcount1 = service.GetCount1Async();
        var tcount2 = service.GetCount2Async();

        await Task.WhenAll(tcount1, tcount2);

        int count1 = tcount1.Result;
        int count2 = tcount2.Result;

        Models.Counts ret = new Counts()
        {
            Count1 = count1,
            Count2 = count2
        };

        return Ok(ret);
    }

с изменениями в услуге

//In the service
public class Service 
{
    public Service() 
    { 
    } 

    public async Task<int> GetCount1()
    {
       using(var context = new MyDbContext()) 
       { 
           return await context.coll1.CountAsync();
       }
    }
    public async Task<int> GetCount2()
    {
       using(var context = new MyDbContext())
       { 
           return await context.coll2.CountAsync();
       } 
    }
}

Есть ли минусы в этом? Это работает и определенно улучшило производительность запроса.

Я довольно плохо знаком с потоками (в данном случае async / wait), поэтому незнаком с потенциальными недостатками или если то, что у меня есть выше, является антипаттерном, но часть меня чувствует, что могут быть проблемы с этой структурой при использовании dbcontext EF ?? Надеюсь, это просто мое невежество, создающее это чувство.

Также отметим, что сначала я переписывал сервис с контекстом как полем класса сервиса; тем не менее, в конечном итоге получил ошибку:

Вторая операция началась в этом контексте до завершения предыдущей асинхронной операции. Используйте 'await', чтобы убедиться, что все асинхронные операции завершены, прежде чем вызывать другой метод в этом контексте. Любые члены экземпляра не гарантированно защищены от потоков.

Изменение жизненного цикла контекста на вызовы методов исправило это, но, видя эту ошибку в целом, я нервничал из-за этой общей стратегии.

1 Ответ

1 голос
/ 20 марта 2019

На мой взгляд, вы делаете это правильно,

  1. Вы не должны кэшировать DbContext, соединения sql кешируются для вас уже под капотом.Это может вызвать всевозможные тонкие ошибки, с которыми вы уже сталкивались.
  2. Контексты не являются поточно-ориентированными.
  3. Они довольно легкие, поэтому производительность не должна быть проблемой.
  4. И их лучше всего помещать в оператор использования с небольшими пакетами работы

В целом, размещение каждого GetCount кажется наилучшим подходом

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...