2016-11-16 5 views
0

Ich möchte eine Auflistung von db connect-Zeichenfolgen durchlaufen und eine Abfrage für alle DBs ausführen, dann jedes IEnumberable-Ergebnis in einer IEnumerable-Liste kombinieren. Die synchrone Version sieht wie folgt aus:Variable Nummer von LINQ-Abfragen asynchron ausführen

public ActionResult ListSites() 
{ 
    ConnectionStringSettingsCollection ConnectionStrings = ConfigurationManager.ConnectionStrings; 

    List<SiteInfoModel> lstSites = new List<SiteInfoModel>(); 

    foreach (ConnectionStringSettings cn in ConnectionStrings) 
    { 
     lstSites.AddRange(getSitesForInstance(cn)); 
    } 

    return View("~/Views/Sites/List.cshtml", lstSites); 
} 

private List<SiteInfoModel> getSitesForInstance(ConnectionStringSettings css) 
{    
    using (STContext db = new STContext(css.ConnectionString)) 
    { 
     IEnumerable<SiteTracker.Data.site_info> sites = db.Sites; 

     return (from s in sites 
        orderby s.name 
        select new SiteInfoModel 
        { 
         instance = css.Name, 
         siteName = formatValue(s.name, s.active), 
         siteUrl = formatValue(s.url, s.active), 
         siteId = s.site_id, 
         isActive = s.active 
        }).ToList();     
    } 
} 

Diese Frage kann mehrere Unterfragen, da es fühlt sich an wie ich mit ein paar verschiedene Dinge bin zu kämpfen: (1) Wie soll getSitesForInstance() geschrieben werden? Sollte es sein

private async Task<List<SiteInfoModel>> getSitesForInstance() 

Wenn es async sein sollte, dann wie schreibe ich den linq Ausdruck. Ich habe versucht, IEnumerable in IQueryable und mit .ToListAsync() zu ändern, aber ich bekomme einen Fehler bei der Projektion eines nicht-anonymen Typs. Kann es ohne asynchrone Task geschrieben werden und die Abfrage trotzdem gleichzeitig über alle Verbindungszeichenfolgen ausgeführt werden? Wenn es so oder so gemacht werden kann, ist es besser oder schlechter.

Der andere Teil der Frage ist (2) wie sollte ListSites() aussehen, wenn geschrieben, um gleichzeitige DB-Aufrufe zu machen? Ich habe mir this example angesehen, aber es bringt mich nicht wirklich zu einer funktionierenden Lösung. Ich habe mit so etwas herumgespielt:

Task<List<SiteInfoModel>>[] tasks = new Task<List<SiteInfoModel>>[ConnectionStrings.Count]; 

for (int i = 0; i < ConnectionStrings.Count - 1; i++) 
{ 
    tasks[i] = getSitesForInstance(ConnectionStrings[i]); 
} 
Task.WaitAll(tasks); 

... aber das konnte nicht funktionieren. Jeder DB-Aufruf gibt eine Liste zurück. Wenn die Ergebnisse aller Aufgaben in der Variablen lstSites kombiniert werden - was das Ansichtsmodell ist - dann wird das Problem/die Frage gelöst/beantwortet.

+0

Nicht sicher, warum Leute stimmen zu schließen - aber ich bin mir auch nicht sicher, warum es nicht funktionieren würde. Was genau hat mit deiner Async-Version nicht funktioniert? Ich mache etwas ähnliches in einer Anwendung, die gut funktioniert. –

Antwort

0

Es gibt 2 Antworten hier

Um alle Ergebnisse in 1 Variable zu bekommen - Sie einfach Parallel.ForEach https://stackoverflow.com/a/12610915/444149 oder https://msdn.microsoft.com/en-us/library/dd460680(v=vs.110).aspx

Beim Sprechen über async .. 1-Erste, was nutzen könnten Sie benötigen ist, Ihre Methode GetSitesForInstance async zu machen. Um dies zu tun nur

  • async Schlüsselwort vor dem Methodennamen
  • Verwendung .ToListAsync() in der Abfrage hinzufügen

2-nd beim Aufruf der Methode - add 'erwartet' vor.

0

hier ist der Code, der diese Arbeit gemacht:

public async Task<ActionResult> ListAsync() 
{    
    ConnectionStringSettingsCollection ConnectionStrings = ConfigurationManager.ConnectionStrings; 

    List<SiteInfoModel> lstSites = new List<SiteInfoModel>(); 

    Task<List<SiteInfoModel>>[] tasks = new Task<List<SiteInfoModel>>[ConnectionStrings.Count]; 

    for (int i = 0; i < ConnectionStrings.Count; i++) 
    { 
     tasks[i] = getSitesForInstanceAsync(ConnectionStrings[i]); 
    } 

    try 
    { 
     Task.WaitAll(tasks.ToArray()); 
    } 
    catch (AggregateException) { } 

    for (int ctr = 0; ctr < tasks.Length; ctr++) 
    { 
     if (tasks[ctr].Status == TaskStatus.Faulted) 
      Console.WriteLine("error occurred in {0}", ConnectionStrings[ctr].Name); 
     else 
     { 
      lstSites.AddRange(tasks[ctr].Result); 
     } 

    } 

    return View("~/Views/Sites/List.cshtml", lstSites); 
} 

private Task<List<SiteInfoModel>> getSitesForInstanceAsync(ConnectionStringSettings css) 
{ 
    return Task.Run(() => getSitesForInstance(css)); 
} 

Visual Studio beschwert, dass ListAsync() nicht das await Schlüsselwort verwenden, aber es funktioniert gut. Ist das ein Problem? Scheint wie Task.WaitAll() macht das Warten auf

Verwandte Themen