LINQ для сущностей более эффективный способ создания нескольких слоев дочернего запроса - PullRequest
0 голосов
/ 02 мая 2018

Я использую EF linq для сущностей. Мне нужно получить несколько слоев элементов для заполнения дерева. Код ниже очень медленный и долго загружается. Запрос, сгенерированный EF, похож на 200 строк (проверил это с помощью SQL Profiler).

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

DBContext db = _DbProvider.GetContext();
List<Level1TreeviewRegion> treeList = (
    from level1Item in db.Level1Table
     join customer in db.Clients on level1Item.Customer_ID equals customer.Customer_ID
     let rentableLocations = (from level4 in db.Location where level4.Rentable_Unit == "J" && level1Item.Customer_ID == level4.Customer_ID && level1Item.Level1_Id == level4.Level1_Id select level4).FirstOrDefault()
     orderby customer.Treeview_sort_level_1_by == "n" ? level1Item.Name : "", customer.Treeview_sort_level_1_by != "n" ? level1Item.Level1_Id : 0
     where level1Item.Customer_ID == customerAreaId && rentableLocations != null
     select new Level1TreeviewRegion
     {
         Record_Number = level1Item.Record_Number,
         LEVEL1_ID = level1Item.Level1_Id,
         LEVEL1_NAME_WithoutCodes = !string.IsNullOrEmpty(level1Item.Name) ? level1Item.Name.Trim() : "",
         LEVEL1_NAME_WithCodes = !string.IsNullOrEmpty(level1Item.Name) ? level1Item.Level1_Id + "-" + level1Item.Name.Trim() : "",
         SearchString = !string.IsNullOrEmpty(level1Item.Name) ? level1Item.Level1_Id + level1Item.Name.Trim() : "",
         Level2List = (from level2 in db.Level2Table
                     let rentableLocations1 = (from level4 in db.Location where level4.Rentable_Unit == "J" && level2.KP_PERSNEEL == level4.Customer_ID && level2.Level1_Id == level4.Level1_Id && level2.Level2_Id == level4.Level2_Id select level4).FirstOrDefault()
                     orderby customer.Treeview_sort_level_2_by == "n" ? level2.Name : "", customer.Treeview_sort_level_2_by != "n" ? level2.Level2_Id : ""
                     where level2.KP_PERSNEEL == customerAreaId && level2.Level1_Id == level1Item.Level1_Id && rentableLocations1 != null
                     select new Level2TreeviewRegion
                     {
                         Record_Number = level2.Record_Number,
                         LEVEL2_CODE = level2.Level2_Id.Trim(),
                         LEVEL2_NAME_WithoutCodes = !string.IsNullOrEmpty(level2.Name) ? level2.Name.Trim() : "",
                         LEVEL2_NAME_WithCodes = !string.IsNullOrEmpty(level2.Name) ? level2.Level2_Id.Trim() + "-" + level2.Name.Trim() : "",
                         SearchString = !string.IsNullOrEmpty(level2.Name) ? level2.Level2_Id.Trim() + level2.Name.Trim() : "",
                         LEVEL1_ID = level2.Level1_Id,
                         Level3List = (from level3 in db.Level3Table
                                          let rentableLocations2 = (from level4 in db.Location where level4.Rentable_Unit == "J" && level3.Customer_ID == level4.Customer_ID && level3.Level1_Id == level4.Level1_Id && level3.Level2_Id == level4.Level2_Id && level3.Level3_Id == level4.Level3_Id select level4).FirstOrDefault()
                                          let objectsInObjectModule = (from om in db.Object_Module where om.Customer_ID == level2.KP_PERSNEEL && om.Level2_Id == level2.Level2_Id && om.Level1_Id == level2.Level1_Id && om.ModuleId == WishModules.VB2.ToString() select om.Level3_Id)
                                          orderby customer.Treeview_sort_level_3_by == "n" ? level3.Name : "", customer.Treeview_sort_level_3_by != "n" ? level3.Level3_Id : ""
                                          where (level3.Level2_Id.Trim() == level2.Level2_Id.Trim() && level3.Customer_ID == customerAreaId
                                                 // extra check with the LEVEL3_MODULE table, it was Object.MJP = J, now it needs a record in the LEVEL3_MODULE table
                                                 //so if no objects are found, it is good (all are visible) OR objects are found, only they are visible
                                                 && (!objectsInObjectModule.Any() || objectsInObjectModule.Contains(level3.Level3_Id)) && rentableLocations2 != null)
                                          select new Level3TreeviewRegion
                                          {
                                              Record_Number = level3.Record_Number,
                                              LEVEL1_ID = level3.Level1_Id,
                                              LEVEL2_CODE = level3.Level2_Id.Trim(),
                                              LEVEL3_CODE = level3.Level3_Id.Trim(),
                                              LEVEL3_NAME_WithoutCodes = !string.IsNullOrEmpty(level3.Name) ? level3.Name.Trim() : "",
                                              LEVEL3_NAME_WithCodes = !string.IsNullOrEmpty(level3.Name) ? level3.Level3_Id.Trim() + "-" + level3.Name.Trim() : "",
                                              SearchString = !string.IsNullOrEmpty(level3.Name) ? level3.Level3_Id.Trim() + level3.Name.Trim() : "",
                                              LEVEL3_PLAATS = level3.City.Trim(),
                                              Ownership = string.IsNullOrEmpty(level3.Ownership) == false && (new[] { "j", "ja", "y", "yes" }).Contains(level3.Ownership.ToLower().Trim()),
                                              Level4List = (from level4 in db.Level4Table
                                                              orderby customer.Treeview_sort_level_4_by == "n" ? level4.Description : "", customer.Treeview_sort_level_4_by != "n" ? level4.Code : ""
                                                              where level4.Rentable_Unit == "J" && level3.Level2_Id.Trim() == level4.Level2_Id.Trim() && level3.Customer_ID == level4.Customer_ID && level3.Level1_Id == level4.Level1_Id && level3.Level3_Id == level4.Level3_Id
                                                              select new Level4TreeviewRegion
                                                              {
                                                                  Record_Number = level4.Record_Number,
                                                                  LEVEL1_ID = level3.Level1_Id,
                                                                  LEVEL2_CODE = level3.Level2_Id.Trim(),
                                                                  LEVEL3_CODE = level3.Level3_Id.Trim(),
                                                                  LEVEL4_CODE = level4.Code.Trim(),
                                                                  LEVEL4_NAME_WithoutCodes = !string.IsNullOrEmpty(level4.Description) ? level4.Description.Trim() : "",
                                                                  LEVEL4_NAME_WithCodes = !string.IsNullOrEmpty(level4.Description) ? level4.Code.Trim() + "-" + level4.Description.Trim() : "",
                                                                  SearchString = !string.IsNullOrEmpty(level4.Description) ? level4.Code.Trim() + level4.Description.Trim() : "",
                                                              }).ToList()
                                          }).ToList()
                     }).ToList()
     }).ToList();

Соответствующая часть базы данных:

Level1Table
[RECNUM] [int] NOT NULL IDENTITY(1, 1),
[Level1_Id] [smallint] NOT NULL,

Level2Table
[RECNUM] [int] NOT NULL IDENTITY(1, 1),
[Level1_Id] [smallint] NOT NULL,
[Level2_Id] [char] (10),
[NAAM1] [char] (60),

Level3Table
[RECNUM] [int] NOT NULL IDENTITY(1, 1),
[Level1_Id] [smallint] NOT NULL,
[Level2_Id] [char] (10),
[Level3_Id] [char] (10),
[NAAM] [char] (60),

Level4Table
[RECNUM] [int] NOT NULL IDENTITY(1, 1),
[Level1_Id] [smallint] NOT NULL,
[Level2_Id] [char] (10) COLLATE,
[Level3_Id] [char] (10) COLLATE,
[Level4_Id] [char] (10) COLLATE,

1 Ответ

0 голосов
/ 02 мая 2018

Вот несколько вещей, которые вы можете сделать:

Переместите логику совокупности свойств в конструкторы:

public class Level1TreeviewRegion
{
    public Level1TreeviewRegion(Level1Item level1Item)
    {
        Record_Number = level1Item.Record_Number;
        LEVEL1_ID = level1Item.Level1_Id;
        LEVEL1_NAME_WithoutCodes = !string.IsNullOrEmpty(level1Item.Name) ? level1Item.Name.Trim() : "";
        LEVEL1_NAME_WithCodes = !string.IsNullOrEmpty(level1Item.Name) ? level1Item.Level1_Id + "-" + level1Item.Name.Trim() : "";
        SearchString = !string.IsNullOrEmpty(level1Item.Name) ? level1Item.Level1_Id + level1Item.Name.Trim() : "";
    }
    //...
}

Сделайте это для всех Level[x]TreeViewRegion классов.

Превратите rentablelocations в число и используйте его в операторе where:

List<Level1TreeviewRegion> treeList = (
        from level1Item in db.Level1Table
        join customer in db.Clients on level1Item.Customer_ID equals customer.Customer_ID            
        orderby 
            customer.Treeview_sort_level_1_by == "n" ? level1Item.Name : "", 
            customer.Treeview_sort_level_1_by != "n" ? level1Item.Level1_Id : "0"
        where level1Item.Customer_ID == customerAreaId &&
        db.Location.Count(level4 =>
            level4.Rentable_Unit == "J" &&
            level1Item.Customer_ID == level4.Customer_ID &&
            level1Item.Level1_Id == level4.Level1_Id
        ) > 0

Сделайте то же самое для rentableLocations1 и rentableLocations2.

objectsInObjectModule не обязательно должен быть частью подзапроса 3-го уровня. Он использует только материал с уровня 2, так что вы можете переместить его на один уровень вверх.

Удалите ToList() звонки повсюду. Вам нужен только последний.

Конечный результат должен выглядеть примерно так:

List<Level1TreeviewRegion> treeList = (
        from level1Item in db.Level1Table
        join customer in db.Clients on level1Item.Customer_ID equals customer.Customer_ID            
        orderby 
            customer.Treeview_sort_level_1_by == "n" ? level1Item.Name : "", 
            customer.Treeview_sort_level_1_by != "n" ? level1Item.Level1_Id : "0"
        where level1Item.Customer_ID == customerAreaId &&
        db.Location.Count(level4 =>
            level4.Rentable_Unit == "J" &&
            level1Item.Customer_ID == level4.Customer_ID &&
            level1Item.Level1_Id == level4.Level1_Id
        ) > 0
        select new Level1TreeviewRegion(level1Item)
        {
            Level2List = (from level2 in db.Level2Table                             
                          let objectsInObjectModule =
                            (
                                from om in db.Object_Module
                                where
                                    om.Customer_ID == level2.KP_PERSNEEL &&
                                    om.Level2_Id == level2.Level2_Id &&
                                    om.Level1_Id == level2.Level1_Id &&
                                    om.ModuleId == WishModules.VB2.ToString()
                                select om.Level3_Id
                            )
                          orderby customer.Treeview_sort_level_2_by == "n" ? level2.Name : "", customer.Treeview_sort_level_2_by != "n" ? level2.Level2_Id : ""
                          where 
                            level2.KP_PERSNEEL == customerAreaId && 
                            level2.Level1_Id == level1Item.Level1_Id && 
                            db.Location.Count(level4 =>
                                level4.Rentable_Unit == "J" &&
                                level2.KP_PERSNEEL == level4.Customer_ID &&
                                level2.Level1_Id == level4.Level1_Id &&
                                level2.Level2_Id == level4.Level2_Id
                            ) > 0
                          select new Level2TreeviewRegion(level2)
                          {
                              Level3List = (from level3 in db.Level3Table                                                                                                
                                            orderby 
                                                customer.Treeview_sort_level_3_by == "n" ? level3.Name : "", 
                                                customer.Treeview_sort_level_3_by != "n" ? level3.Level3_Id : ""
                                            where 
                                                (
                                                    level3.Level2_Id.Trim() == level2.Level2_Id.Trim() && 
                                                    level3.Customer_ID == customerAreaId
                                                   // extra check with the LEVEL3_MODULE table, it was Object.MJP = J, now it needs a record in the LEVEL3_MODULE table
                                                   //so if no objects are found, it is good (all are visible) OR objects are found, only they are visible
                                                   && (
                                                        !objectsInObjectModule.Any() || 
                                                        objectsInObjectModule.Contains(level3.Level3_Id)
                                                      ) 
                                                   && db.Location.Count(level4 =>
                                                    level4.Rentable_Unit == "J" &&
                                                    level3.Customer_ID == level4.Customer_ID &&
                                                    level3.Level1_Id == level4.Level1_Id &&
                                                    level3.Level2_Id == level4.Level2_Id &&
                                                    level3.Level3_Id == level4.Level3_Id) > 0
                                                )
                                            select new Level3TreeviewRegion(level3)
                                            {
                                                Level4List = (from level4 in db.Level4Table
                                                              orderby 
                                                              customer.Treeview_sort_level_4_by == "n" ? level4.Description : "", 
                                                              customer.Treeview_sort_level_4_by != "n" ? level4.Code : ""
                                                              where 
                                                                level4.Rentable_Unit == "J" && 
                                                                level3.Level2_Id.Trim() == level4.Level2_Id.Trim() && 
                                                                level3.Customer_ID == level4.Customer_ID && 
                                                                level3.Level1_Id == level4.Level1_Id && 
                                                                level3.Level3_Id == level4.Level3_Id
                                                              select new Level4TreeviewRegion(level4, level3))
                                            })
                          })
        }).ToList();

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

...