2016-10-20 3 views
1

Ich versuche, eine Lambda Select mit Entity Framework aus einer Tabelle in ein neues Modell durchzuführen, aber ich muss eine asynchrone Methode aufrufen können, um eine Eigenschaft für jede Instanz in der Rückkehr zu füllen eingestellt:Wie erwartet während Select in einem Lambda

await Task.WhenAll(_context.UserContacts.Where(uc => uc.UserId == user.Id).Select(async uc => new MailContact 
      { 
       Email = uc.Contact.Email, 
       UserId = uc.Contact.UserId, 
       ContactId = uc.Contact.Id, 
       Name = uc.Contact.UserId != null ? await _graphService.GetUserByIdAsync(uc.Contact.UserId) : null; 
      } 

ich verstehe, dass Linq begrenzte Unterstützung für await/Async und ich habe sah einige andere Beispiele, wo die auf Stackoverflow asynchronen Teil in eine separate Schleife bewegt hat, zum Beispiel:

How to await a method in a Linq query

T[] data = await Task.WhenAll(contacts.Select(c => LoadDataAsync(c))); 

Diese Methode lässt mich jedoch nicht das Objekt aktualisieren, das als "c" bezeichnet wird, es sei denn, ich überlasse den Verweis, was bei asynchronen Methoden nicht zulässig ist.

Kann jemand den effizientesten Weg erklären, die Namenseigenschaft richtig zu füllen?

Antwort

0

ich beschlossen dies durch einen Wrapper zu erstellen:

private async Task<string> GetDisplayName(string userId) 
    { 
     if (string.IsNullOrEmpty(userId)) return null; 
     var contactUser = await _graphService.GetUserByIdAsync(userId); 
     return contactUser.DisplayName; 
    } 

und die Änderung der Zuordnung zu diesem:

Name = u.UserId != null ? await GetDisplayName(u.UserId) : null 
4

Sie müssen nur die sekundäre Lookup in LINQ-to-Objects tun, nicht LINQ-to-Entities:

// LINQ-to-Entities 
var users = await _context.UserContacts 
    .Where(uc => uc.UserId == user.Id) 
    .Select(uc => new 
    { 
     uc.Contact.Email, 
     uc.Contact.UserId, 
     ContactId = uc.Contact.Id, 
    }) 
    .ToListAsync(); 

// LINQ-to-Objects 
var lookupTasks = users.Select(async u => new 
    { 
     u.Email, 
     u.UserId, 
     u.ContactId, 
     Name = u.UserId != null ? await _graphService.GetUserByIdAsync(u.UserId) : null; 
    }); 
return await Task.WhenAll(lookupTasks); 

Die Idee ist, dass Sie so viel Logik in die Ausgangs LINQ-to-Entities-Abfrage drücken einschließlich Filterung und Projektion. Dann führen Sie es aus (ToListAsync).

Dann nehmen Sie Ihre DB-Ergebnisse und die sekundäre Suche.

+0

Ich glaube, Sie 'Rückkehr erwarten Task.WhenAll (lookupTasks) verwenden gemeint haben kann; 'Not' Rückkehr warten Task.WhenAll (Aufgaben); ' –

+0

@MetroSmurf: Fest, danke! –

+0

Richtig, verstanden. Es fiel mir nicht ein, alle Eigenschaften in eine neue dynamische Eigenschaft neu zu wählen :) – RNDThoughts

Verwandte Themen