我正在使用EF linq实体。我需要获得多层项目来填充树视图。下面的代码非常慢,需要很长时间才能加载。 EF生成的查询类似于200行(使用SQL事件探查器进行检查)。
我想知道是否有更有效的方法,可能有多个查询或代码重新排序。这种表现并不是真的可以接受。
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,
答案 0 :(得分:0)
您可以执行以下操作:
将属性群的逻辑移动到构造函数中:
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级子查询的一部分。它只使用level2中的东西,所以你可以将它向上移动一级。
删除所有地方的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();
根据过去的经验,当您最终得到看起来非常相似的复杂查询和逻辑时,通常意味着您需要退后一步并重新考虑您的设计。