Мне интересно, как правильно использовать класс 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
}