Использование OData DataServiceContext - PullRequest
0 голосов
/ 02 апреля 2019

Мне интересно, как правильно использовать класс DataServiceContext.Должен ли я создать новый экземпляр для каждой единицы работы и / или области, например:

public SomeEntity GetSomeEntities()
{ 
   DataServiceContext context = new DataServiceContext(...);
   DataServiceQuery<SomeEntity> query = context.SomeEntity
      .Where(x => x.SomeProperty == someValue);

   IEnumerable<SomeEntity> someEntities = await Task.Factory.FromAsync(
      query.BeginExecute, query.EndExecute, null);

   return someEntities.ToList();
}

Или я должен использовать общий экземпляр:

private readonly DataServiceContext context = new DataServiceContext(...);

public SomeEntity GetSomeEntities()
{ 
   DataServiceQuery<SomeEntity> query = context.SomeEntity
      .Where(x => x.SomeProperty == someValue);

   IEnumerable<SomeEntity> someEntities = await Task.Factory.FromAsync(
      query.BeginExecute, query.EndExecute, null);

   return someEntities.ToList();
}

Я понимаю, что в случаеВ контексте EntityFramework вы используете первый подход, но я не уверен насчет случая OData - в частности, не приведет ли постоянное воссоздание контекста к исчерпанию сокета так же, как воссоздание HttpClient.

Смежный вопрос касается потоковой безопасности контекста - безопасно ли использовать один и тот же контекст из нескольких параллельных потоков, например:

DataServiceContext context = new DataServiceContext(...);
List<Task<IEnumerable<SomeEntity>>> downloadTasks = new List<Task<IEnumerable<SomeEntity>>>();

using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource())
{
   foreach (var batch in someEntitiesList.Batch(_defaultBatchSize))
   {
      if (cancellationTokenSource.IsCancellationRequested)
         break;

      string filter = string.Join(" or ", batch.Select(i => $"(Id eq '{i.Id}')"));

      Task<IEnumerable<SomeEntity>> task = Task.Run(() =>
      {
         try
         {
            DataServiceQuery<SomeEntity> query = context.SomeEntity
               .AddQueryOption("$filter", filter)
               .OrderBy(x => x.Id)
               as DataServiceQuery<SomeEntity>;

               IEnumerable<SomeEntity> someEntities = query.Execute();

               return someEntities;
         } 
         catch(Exception)
         {
            cancellationTokenSource.Cancel();
            throw;
         }
      }, cancellationTokenSource.Token);

      downloadTasks.Add(task);
   }

   await Task.WhenAll(downloadTasks);
   //do something with results
}

Или мне нужно использовать новый контекст для каждой задачи, например:

List<Task<IEnumerable<SomeEntity>>> downloadTasks = new List<Task<IEnumerable<SomeEntity>>>();

using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource())
{
   foreach (var batch in someEntitiesList.Batch(_defaultBatchSize))
   {
      if (cancellationTokenSource.IsCancellationRequested)
         break;

      string filter = string.Join(" or ", batch.Select(i => $"(Id eq '{i.Id}')"));

      Task<IEnumerable<SomeEntity>> task = Task.Run(() =>
      {
         try
         {
            DataServiceContext context = new DataServiceContext(...);

            DataServiceQuery<SomeEntity> query = context.SomeEntity
               .AddQueryOption("$filter", filter)
               .OrderBy(x => x.Id)
               as DataServiceQuery<SomeEntity>;

               IEnumerable<SomeEntity> someEntities = query.Execute();

               return someEntities;
         } 
         catch(Exception)
         {
            cancellationTokenSource.Cancel();
            throw;
         }
      }, cancellationTokenSource.Token);

      downloadTasks.Add(task);
   }

   await Task.WhenAll(downloadTasks);
   //do something with results
}
...