C# linq到实体更有效地构建多层子查询的方法

C# linq到实体更有效地构建多层子查询的方法,c#,linq-to-sql,entity-framework-6,linq-to-entities,C#,Linq To Sql,Entity Framework 6,Linq To Entities,我正在使用EF linq转换实体。我需要得到填充树视图的多层项目。下面的代码非常慢,需要很长时间才能加载。EF生成的查询大约有200行(使用SQL Profiler检查) 我想知道是否有更有效的方法来实现这一点,可能是通过多个查询或代码重新排序。这种方式的性能实际上不可接受 DBContext db = _DbProvider.GetContext(); List<Level1TreeviewRegion> treeList = ( from level1Item in db

我正在使用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();

以下是您可以做的几件事:

将属性填充的逻辑移到构造函数中:

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

根据过去的经验,当您最终遇到复杂的查询和逻辑时,它们看起来非常相似,这通常意味着您需要后退一步,重新考虑您的设计。

那些
ToList()
调用无助于您的速度。。。你只想实现结果,对吗?因此,您应该只有一个
.ToList()
调用(即最后一个调用)。属性中的逻辑也可以从查询中删除,并转换为只读计算属性,以按需检查null。您可以发布数据库架构吗?这将为我们省去反汇编代码的麻烦。好的,我更新了相关的数据库信息和linq查询,使其更加具体
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
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();