2014-09-26 4 views
0

Я пытаюсь выполнить цикл через результирующий набор, запустить запрос для извлечения данных, а затем добавить эти данные в список и вернуть его.Возвращение списка объектов асинхронно

Проблема заключается в том, что я пытаюсь сделать это асинхронно, и я получаю сообщение об ошибке:

'System.Collections.Generic.List' does not contain a definition for 'ToListAsync' and the best extension method overload 'System.Data.Entity.QueryableExtensions.ToListAsync(System.Linq.IQueryable)' has some invalid arguments

Вот код для метода:

public async Task<List<IHFData>> GetHFServiceData(string wtTransfereeId) 
{ 
    var hfDataList = new List<HFData>(); 

    Parallel.ForEach(aauthorizationList, item => 
    { 
     // code to retrieve data from database (truncated) 
     HFData hfData = Db.hfAuthorizations.AsNoTracking()....SingleOrDefault(); 

     hfDataList.Add(hfData); 
    } 

    return await hfDataList.ToListAsync(); // errors on this line 
} 

Как я могу построить и возврат мой список асинхронно?

+1

кажется, что 'ToListAsync' является [Entity Framework метод] (http://msdn.microsoft .com/en-us/library/dn220261 (v = vs.113) .aspx) – gunr2171

ответ

3

Есть несколько ОГРОМНЫХ проблем с вашим кодом.

Во-первых, вы вызываете hfDataList.Add внутри Parallel.ForEach, List<T> не является потокобезопасным, вы не можете вызвать Add без блокировки.

Во-вторых, поскольку сообщение об ошибке ToListAsync может быть вызвано только для типа, имеющего интерфейс IQueryable<T>, вы вызываете его на List<T>, который не реализует этот интерфейс.

Правильный способ сделать запрос будет

public Task<List<IHFData>> GetHFServiceData(string wtTransfereeId) 
{ 
    return Db.hfAuthorizations.AsNoTracking()....ToListAsync() 
} 

Вам нужно будет изменить все, что было в ...., что вы приняли, чтобы вернуть набор результатов вместо одного результата за один раз.

Также не было необходимости в await, это была последняя строка в вашей функции, вы можете просто вернуть задачу directly и упростить сгенерированный код и уменьшить накладные расходы.


Если вы не можете изменить его до заданного запроса (и вы действительно должны попробовать, это позволит значительно повысить производительность), то способ сделать это ваш старый способ заключается в уронить параллельно (рамки Entity не может обрабатывать ее) и просто сделать нормальный цикл Еогеаспа, а затем ждать от версии асинхронной из SingleOrDefault

public async Task<List<IHFData>> GetHFServiceData(string wtTransfereeId) 
{ 
    var hfDataList = new List<HFData>(); 

    foreach(var item in aauthorizationList) 
    { 
     // code to retrieve data from database (truncated) 
     HFData hfData = await Db.hfAuthorizations.AsNoTracking()....SingleOrDefaultAsync(); //This method is now async. 

     hfDataList.Add(hfData); 
    } 

    //just return the list when you are done. 
    return hfDataList; 
} 
+0

Да, я знаю, что было бы проще иметь только один запрос linq и вызвать ToListAsync(); однако причина, по которой мы используем foreach, состоит в том, что она слишком сложна для одного запроса.Можно ли использовать foreach для построения и возврата списка async? – user1477388

+1

@ user1477388 Я обновил ответ, в котором показано, как сделать это ближе к тому, как это сделает ваш старый способ. –

+0

Вопрос об этом: при отладке, похоже, что код попадает в цикл foreach, а затем просто направляется в обратную линию, поэтому 'hfDataList' всегда пуст. Вы не знаете, почему он пропустил бы код async/add? – user1477388

5

Как указано в сообщении об ошибке, для создания списка асинхронно не существует метода List. В любом случае у вас уже есть список.

Также небезопасно добавлять элементы в список из нескольких потоков, как вы делаете это из своего параллельного цикла foreach.

Вы также не должны выполнять запрос базы данных для каждого элемента в своей коллекции в первую очередь. Вместо этого вы должны выполнить запрос single, который извлекает все элементы, которые вам нужны, на основе информации из списка, который у вас есть. Этот запрос должен завершиться вызовом ToListAsync.

Здесь также нет необходимости использовать метод async, вы можете просто сразу вернуть результат ToListAsync.

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