2015-02-07 2 views
1

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

public async Task<IEnumerable<Member>> GetAllMembersAsync() 
{ 
    var members = Repository.GetAll<Member>(); 

    return await Task.Run(() => members.ToListAsync()); 
} 

По неизвестной причине (? Может быть ошибка), я должен использовать Task.Run для того, чтобы сделать эту работу (репозиторий просто возвращает DbSet<Member>.Если я этого не сделаю, мой пользовательский интерфейс будет вечно вечно.

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

A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe. 

Как вы видите, я уже использую await.

Есть ли способ решить эту проблему, поэтому я могу на самом деле выполнить 2 операции с базой данных одновременно и поэтому они работают в порядке?

EDIT: код, который вызывает это:

private async void LoadMembers() 
{ 
    try 
    { 
     var members = await MemberService.GetAllMembersAsync(); 

     Members = new ObservableCollection<Member>(members); 
    } 
    catch (EntityException) 
    { 
     // connection lost? 
    } 

} 
+0

Можете ли вы показать код, который звонит ваш GetAllMembersAsync) '' метод (? –

+0

Несомненно, я добавил его, спасибо :) – Bv202

+0

Как использовать '.ContinueWith' для второго асинхронного вызова? Вам нужно будет начать еще одну задачу в продолжении, но по крайней мере эти задачи будут связаны друг с другом. Так много способов скинуть этот кот, хотя ... – code4life

ответ

2

Ответ отрицательный. Поскольку ошибка предполагает, что вы не можете одновременно выполнять две параллельные операции EF. Вот более подробный ответ: Does Entity Framework support parallel async queries?

Кроме того, вам не нужно использовать Task.Run для решения проблемы, которая, как представляется, является проблемой взаимоблокировки. Просто используйте ConfigureAwait, чтобы убедиться, что операция async не нуждается в UI SynchronizationContext. (Также, убедитесь, что вы не блокируете на async код с Task.Wait или Task.Result):

public async Task<IEnumerable<Member>> GetAllMembersAsync() 
{ 
    return await Repository.GetAll<Member>().ToListAsync().ConfigureAwait(false); 
} 

private async void LoadMembers() 
{ 
    try 
    { 
     var members = await MemberService.GetAllMembersAsync(); 
     Members = new ObservableCollection<Member>(members); 
    } 
    catch (EntityException) 
    { 
     // connection lost? 
    } 
} 
+0

Так что же это: я создаю Singleton под названием SIngleTask для использования в операциях с базой данных. Этот Singleton гарантирует, что активна только одна задача. Если нет, он использует ContinueWith. Это хороший вариант? – Bv202

+0

@ Bv202 Существуют более простые способы сериализации операций async. Вы можете просто использовать 'SemaphoreSlim.WaitAsync', сконфигурированный с 1. – i3arnon

+0

Я бы разрешил тупик, удалив ожидание, которое наверняка где-то скрыто. ConfigureAwait (false) - неправильное обращение. – usr

1

Я думаю, что вы находитесь в тупиковой ситуации, потому что вы не используете configureawait (истина) должным образом. Вы можете сделать

public async Task<IEnumerable<Member>> GetAllMembersAsync() 
{ 
    var members = Repository.GetAll<Member>(); 

    return await Task.Run(() => members.ToListAsync()); 
} 

private async void LoadMembers() 
{ 
    try 
    { 
     var members = await MemberService.GetAllMembersAsync().ConfigureAwait(true); 

     Members = new ObservableCollection<Member>(members); 
    } 
    catch (EntityException) 
    { 
    // connection lost? 
    } 

} 

после завершения операции, а если выполняется из GUI потока, GUI поток возобновится.

+0

Большое спасибо, кажется, это трюк! Зачем мне нужен этот дополнительный метод? Разве это не должно быть поведение по умолчанию? – Bv202

+0

Не ждите, если я это сделаю, мой пользовательский интерфейс зависает при извлечении данных ... – Bv202

+0

var members = await MemberService.GetAllMembersAsync(). ConfigureAwait (true); правильнее. Причина в том, что ваш наблюдаемый сборник следующий в строке и используется для операций привязки к потоку графического интерфейса. Это в сочетании с var list = await members.ToListAsync().ConfigureAwait (false) также работает. Мне нравится явно выполнять эти вызовы configureawait, даже если это не нужно, есть значение по умолчанию, потому что оно показывает намерение. Если это решает вашу проблему, пожалуйста, отметьте как ответ ;-) –

Смежные вопросы