Заполнение свойства дочерней коллекции подзапросом LINQ - PullRequest
1 голос
/ 02 марта 2009

Я довольно новичок в LINQ в целом, но мне удалось все выяснить, чтобы получить результат, который я хочу / нужен. Приведенный ниже запрос LINQ2SQL дает желаемые результаты, в которых есть объекты Location, каждый со своей собственной коллекцией Units. Первоначальные объявления переменных выполняются для установки значений, к которым мне нужно запрашивать, и они не должны относиться к моей проблеме, но необходимы для контекста.

Проблема, с которой я столкнулся, состоит в том, что существует более 400 местоположений, и в настоящее время у меня структурирован запрос, он обращается к базе данных для каждого вместо одного большого запроса. Это приводит к значительному снижению производительности, и для возврата полного результата требуется более 30 секунд, что недопустимо. У меня есть SQL-запрос хранимой процедуры, который возвращает результаты всего за секунду или две.

Есть ли способ реструктурировать этот запрос, чтобы я не обращался к базе данных для каждого местоположения? Я уверен, что это вызвано дополнительным «ToList ()» в подзапросе Units, но я не знаю, как сформировать результат без ToList (). Любая настройка производительности будет ОГРОМНОЙ помощью. Спасибо за любую помощь!

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())

ОБНОВЛЕНИЕ (03.03.2009 10:58): Мне удалось вернуть данные в одном запросе, используя запрос ниже, но это результат плоской таблицы. Как я могу сформировать это так, чтобы организационная структура стала иерархической в ​​каждом месте? Я считаю, что хочу использовать что-то вроде «Group Join», но я не знаю, как это работает. Информация о местоположении - все до столбца «OrgID». Мне нужно сформировать эти данные в коллекцию Locations, каждая из которых имеет свойство «Units», которое представляет собой коллекцию организаций, находящихся в этом месте. Любое руководство?

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})

Ответы [ 2 ]

1 голос
/ 02 марта 2009

Вместо того, чтобы выставлять элемент как List<T>, измените тип свойства на IEnumerable<T> или IQueryable<T>. Затем вы можете удалить вызовы ToList, и ваш запрос должен быть полностью выполнен на сервере за один раз.

Кроме того, этот тип кода - то, где LINQ to SQL начинает разрушаться, IMO. Я думаю, что если у вас есть хранимая процедура, которая даст вам желаемый результат, вы должны использовать ее, а LINQ to SQL просто обрабатывает отображение возвращаемых данных вашим объектам.

0 голосов
/ 04 марта 2009

Итак, я закончил переделывать вещи и нашел следующее решение, которое запрашивает базу данных только дважды и работает НАМНОГО быстрее:

    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())

Спасибо за помощь casperOne!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...