2009-03-02 14 views
1

Ich bin ziemlich neu zu LINQ im Allgemeinen, aber ich habe es geschafft, Dinge herauszufinden, bis jetzt das Ergebnis, das ich will/brauche. Die folgende LINQ2SQL-Abfrage erzeugt die gewünschten Ergebnisse, in denen Standortobjekte mit jeweils einer eigenen Sammlung von Einheiten enthalten sind. Die anfänglichen Variablendeklarationen werden durchgeführt, um die Werte einzurichten, von denen abgefragt werden muss, und die für mein Problem nicht relevant sind, aber für den Kontext benötigt werden.Auffüllen von Child-Collection-Eigenschaft mit LINQ-Unterabfrage

Das Problem, das ich habe, ist, dass es mehr als 400 Standorte gibt, und die aktuelle Art, wie ich die Abfrage strukturiert habe, trifft die Datenbank für jeden einzelnen statt einer großen Abfrage. Dies führt dazu, dass die Leistung stark leidet, wobei 30+ Sekunden benötigt werden, damit das volle Ergebnis zurückkommt, was inakzeptabel ist. Ich habe eine gespeicherte Prozedur SQL-Abfrage, die die Ergebnisse in nur ein oder zwei Sekunden zurückgibt.

Gibt es eine Möglichkeit, diese Abfrage neu zu strukturieren, so dass ich nicht die Datenbank für jeden Standort treffe? Ich bin sicher, dass es durch die zusätzliche "ToList()" in der Units-Unterabfrage verursacht wird, aber ich weiß nicht, wie ich das Ergebnis ohne die ToList() gestalten kann. Jede Optimierung der Performance wäre eine riesige Hilfe. Danke für jede Hilfe!

Dim curNames1 = (From ons In dc.organization_names _ 
    Where ons.eff_date <= ssDate _ 
    Order By ons.eff_date Descending _ 
    Group ons By ons.organization_id Into gNames = Group _ 
    Select New With { _ 
    Key .Key = organization_id, _ 
    .Result = gNames.Take(1)}) _ 
    .SelectMany(Function(a) (a.Result)) 

Dim curLocs1 = (From oLocs In dc.organization_locations _ 
    Where oLocs.eff_date <= ssDate _ 
    Order By oLocs.eff_date Descending _ 
    Group oLocs By oLocs.organization_id Into gLocs = Group _ 
    Select New With { _ 
    Key .Key = organization_id, _ 
    Result = gLocs.Take(1)}) _ 
    .SelectMany(Function(a) (a.Result)) 

Dim curStatuses1 = (From oEDate In dc.organization_conversion_dates _ 
    Where oEDate.edate <= ssDate _ 
    Order By oEDate.edate Descending _ 
    Group oEDate By oEDate.organization_id Into gEDates = Group _ 
    Select New With { _ 
    Key .Key = organization_id, _ 
    .Result = gEDates.Take(1)}) _ 
    .SelectMany(Function(a) (a.Result)) 

Dim curCommand1 = (From oCommand In dc.organization_service_assigneds _ 
    Where oCommand.eff_date <= ssDate _ 
    Order By oCommand.eff_date Descending _ 
    Group oCommand By oCommand.organization_id Into gCmds = Group _ 
    Select New With { _ 
    Key .Key = organization_id, _ 
    .Result = gCmds.Take(1)}) _ 
    .SelectMany(Function(a) (a.Result)) 

Dim curComponent1 = (From oCompo In dc.organization_compos _ 
    Where oCompo.eff_date <= ssDate _ 
    Order By oCompo.eff_date Descending _ 
    Group oCompo By oCompo.organization_id Into gCompos = Group _ 
    Select New With { _ 
    Key .Key = organization_id, _ 
    .Result = gCompos.Take(1)}) _ 
    .SelectMany(Function(a) (a.Result)) 

ss.Locations = New ObservableCollection(Of Location)((_ 
    From map In dc.MapBackgrounds Where map.MapID = options.Map _ 
    Let Locs = map.Schemes.SchemeLocations _ 
    From SchemeLoc In Locs _ 
    Where (options.Locations.Count = 0 Or _ 
     options.Locations.Contains(SchemeLoc.Location.ID)) _ 
    Select New Location With { _ 
    .ID = SchemeLoc.Location.ID, .Name = SchemeLoc.Location.Location, _ 
    .Y = SchemeLoc.Y, .X = SchemeLoc.X, _ 
    .Country = New Country With _ 
    {.ID = SchemeLoc.Location.Countries.ID, _ 
    .Name = SchemeLoc.Location.Countries.country}, _ 
    .State = If(SchemeLoc.Location.State = -1, Nothing, _ 
    New USState With {.ID = SchemeLoc.Location.States.ID, _ 
    .Name = SchemeLoc.Location.States.state, _ 
    .Abbreviation = SchemeLoc.Location.States.state}), _ 
    .Units = New ObservableCollection(Of MillitaryUnit)((_ 
    From curLoc In curLocs1 _ 
    Where curLoc.location = SchemeLoc.Location.ID _ 
    From curName In curNames1 _ 
    Where curName.organization_id = curLoc.organization_id _ 
    And (options.UnitSizes.Count = 0 Or _ 
     options.UnitSizes.Contains(curName.UnitSize)) _ 
    And (options.UnitTypes.Count = 0 Or _ 
    options.UnitTypes.Contains(curName.UnitType)) _ 
    From curEDate In curStatuses1 _ 
    Where curEDate.organization_id = curLoc.organization_id _ 
    And (options.Statuses.Count = 0 Or _ 
    options.Statuses.Contains(curEDate.status)) _ 
    From curCmd In curCommand1 _ 
    Where curCmd.organization_id = curLoc.organization_id _ 
    And (options.Commands.Count = 0 Or _ 
    options.Commands.Contains(curCmd.service_assigned)) _ 
    From curCompo In curComponent1 _ 
    Where curCompo.organization_id = curLoc.organization_id _ 
    And (options.Components.Count = 0 Or _ 
    options.Components.Contains(curCompo.compo)) _ 
    From curTable In curLoc.Organization.organization_tables _ 
    Where curTable.organization_id = curLoc.organization_id _ 
    And (options.Tables.Count = 0 Or _ 
    (options.Tables.Contains(curTable.table_id) Or _ 
    curTable.Tables.Any(Function(a) (options.Tables.Contains(a.parent_id))))) _ 
     Select New MillitaryUnit With { _ 
     .ID = curLoc.organization_id, _ 
     .Name = curName.name, _ 
     .IconPath = curName.icon, _ 
     .ConversionStatus = curEDate.Status1.status, _ 
     .ServiceCommand = curCmd.Service_Assigneds.service_assigned, _ 
     .Component = curCompo.Components.compo}).Distinct().ToList())}).ToList()) 

UPDATE (2009.03.03 10.58): ich es geschafft, die Daten zurück in eine Abfrage mit der Abfrage unten zu bekommen, aber es ist ein flacher Tisch Ergebnis. Wie kann ich das so gestalten, dass die Organisation unter jedem Standort hierarchisch wird? Ich glaube, ich möchte etwas wie "Group Join" verwenden, aber ich weiß nicht, wie das funktioniert. Die Ortsinfo ist alles bis zur Spalte "OrgID". Ich muss diese Daten in eine Sammlung von Standorten einteilen, die jeweils eine "Units" -Eigenschaft haben, die eine Sammlung der Organisationen darstellt, die sich an diesem Ort befinden. Irgendeine Anleitung?

Dim locationsquery = (From map In dc.MapBackgrounds Where map.MapID = 1 Let Locs = map.Schemes.SchemeLocations _ 
        From SchemeLoc In Locs Join curLoc In curLocs1 On SchemeLoc.LocID Equals curLoc.location _ 
        Join curName In curNames1 On curLoc.organization_id Equals curName.organization_id _ 
        Join curStatus In curStatuses1 On curLoc.organization_id Equals curStatus.organization_id _ 
        Join curCommand In curCommand1 On curLoc.organization_id Equals curCommand.organization_id _ 
        Join curComponent In curComponent1 On curLoc.organization_id Equals curComponent.organization_id _ 
        Select New With {.LocationID = SchemeLoc.LocID, .X = SchemeLoc.X, .Y = SchemeLoc.Y, _ 
             .LocationName = SchemeLoc.Location.Location, _ 
             .CountryID = SchemeLoc.Location.Countries.id, .CountryName = SchemeLoc.Location.Countries.country, _ 
             .StateID = SchemeLoc.Location.State, .StateName = SchemeLoc.Location.States.state, .StateAbbrev = SchemeLoc.Location.States.state, _ 
             .OrgID = curLoc.organization_id, _ 
             .OrgName = curName.name, _ 
             .OrgLocID = curLoc.location, _ 
             .IconPath = curName.icon, _ 
             .ConversionStatus = curStatus.status1.status, _ 
             .CurCmd = curCommand.service_assigneds.service_assigned, _ 
             .CurCompo = curComponent.components.compo}) 

Antwort

0

So landete ich redoing Dinge auf und kam mit der folgenden Lösung auf, die nur die Datenbank zweimal abfragt und ist viel schneller:

Dim locationsOnly = (From map In dc.MapBackgrounds Where map.MapID = 1 Let Locs = map.Schemes.SchemeLocations _ 
            From SchemeLoc In Locs _ 
            Where (options.Locations.Count = 0 Or options.Locations.Contains(SchemeLoc.LocID)) _ 
            Select New With {.LocationID = SchemeLoc.LocID, .X = SchemeLoc.X, .Y = SchemeLoc.Y, _ 
             .LocationName = SchemeLoc.Location.Location, _ 
             .CountryID = SchemeLoc.Location.Countries.ID, .CountryName = SchemeLoc.Location.Countries.country, _ 
             .StateID = SchemeLoc.Location.State, .StateName = SchemeLoc.Location.States.state, .StateAbbrev = SchemeLoc.Location.States.state}).ToList() 


Dim orgsOnly = (From curLoc In curLocs1 _ 
        Join curName In curNames1 On curLoc.organization_id Equals curName.organization_id _ 
        Join curStatus In curStatuses1 On curLoc.organization_id Equals curStatus.organization_id _ 
        Join curCommand In curCommand1 On curLoc.organization_id Equals curCommand.organization_id _ 
        Join curComponent In curComponent1 On curLoc.organization_id Equals curComponent.organization_id _ 
        Join curTable In dc.organization_tables On curLoc.organization_id Equals curTable.organization_id _ 
        Where (options.UnitSizes.Count = 0 Or options.UnitSizes.Contains(curName.UnitSize)) _ 
         And (options.UnitTypes.Count = 0 Or options.UnitTypes.Contains(curName.UnitType)) _ 
         And (options.Statuses.Count = 0 Or options.Statuses.Contains(curStatus.status)) _ 
         And (options.Commands.Count = 0 Or options.Commands.Contains(curCommand.service_assigned)) _ 
         And (options.Components.Count = 0 Or options.Components.Contains(curComponent.compo)) _ 
         And (options.Tables.Count = 0 Or (options.Tables.Contains(curTable.table_id) Or curTable.Tables.Any(Function(a) (options.Tables.Contains(a.parent_id))))) _ 
        Select New With {.OrgLocID = curLoc.location, _ 
         .MilUnit = New MillitaryUnit With { _ 
         .ID = curLoc.organization_id, _ 
         .Name = curName.name, _ 
         .IconPath = curName.icon, _ 
         .ConversionStatus = curStatus.Status1.status, _ 
         .ServiceCommand = curCommand.Service_Assigneds.service_assigned, _ 
         .Component = curComponent.Components.compo}}).Distinct().ToList() 


ss.Locations = New System.Collections.ObjectModel.ObservableCollection(Of Location)((From loc In locationsOnly _ 
        Group Join org In orgsOnly On loc.LocationID Equals org.OrgLocID Into Orgs = Group _ 
        Select New Location With { _ 
         .ID = loc.LocationID, _ 
         .Name = loc.LocationName, _ 
         .X = loc.X, _ 
         .Y = loc.Y, _ 
         .Country = New Country With {.ID = loc.CountryID, .Name = loc.CountryName}, _ 
         .State = New USState With {.ID = loc.StateID, .Name = loc.StateName, .Abbreviation = loc.StateAbbrev}, _ 
         .Units = New System.Collections.ObjectModel.ObservableCollection(Of MillitaryUnit)((From curOrg In Orgs _ 
          Select curOrg.MilUnit).ToList())}).ToList()) 

Danke für Ihre Hilfe casperOne!

1

Anstatt das Element als ein List<T> des Aussetzens, die Art des Objektes zu einer IEnumerable<T> ändern oder eine IQueryable<T>. Dann können Sie die Aufrufe von ToList entfernen und Ihre Abfrage sollte vollständig auf dem Server auf einmal ausgeführt werden können.

Auch diese Art von Code ist, wo LINQ to SQL beginnt zu brechen, IMO. Ich denke, wenn Sie über eine gespeicherte Prozedur verfügen, die Ihnen die gewünschten Ergebnisse liefert, sollten Sie diese verwenden und LINQ to SQL die Zuordnung der zurückgegebenen Daten zu Ihren Objekten übernehmen.

+0

Ich schaffte es, alles in einer Abfrage zurück zu bekommen. Kannst du mir bitte meinen bearbeiteten Post ansehen, um zu sehen, wo ich mit der einen Frage feststecke? Vielen Dank! – Tom

Verwandte Themen