我有以下代码,这是不正常的:
TPM_USER user = UserManager.GetUser(context, UserId);
var tasks = (from t in user.TPM_TASK
where t.STAGEID > 0 && t.STAGEID != 3 && t.TPM_PROJECTVERSION.STAGEID <= 10
orderby t.DUEDATE, t.PROJECTID
select t);
第一行,UserManager.GetUser
只是在数据库中进行简单的查找以获得正确的TPM_USER
记录。但是,第二行会导致各种 SQL 混乱。
首先,它在这里执行了两条 SQL 语句。第一个抓取与该用户链接的每一行,TPM_TASK
有时是数万行:
SELECT
-- Columns
FROM TPMDBO.TPM_USERTASKS "Extent1"
INNER JOIN TPMDBO.TPM_TASK "Extent2" ON "Extent1".TASKID = "Extent2".TASKID
WHERE "Extent1".USERID = :EntityKeyValue1
对于有大量任务的用户,此查询大约需要 18 秒。我希望 WHERE 子句也包含 STAGEID 过滤器,这将删除大部分行。
接下来,它似乎对上面列表中的每一对执行一个新查询TPM_PROJECTVERSION
:
SELECT
-- Columns
FROM TPMDBO.TPM_PROJECTVERSION "Extent1"
WHERE ("Extent1".PROJECTID = :EntityKeyValue1) AND ("Extent1".VERSIONID = :EntityKeyValue2)
尽管这个查询很快,但如果用户在一大堆项目中有任务,它也会执行数百次。
我想生成的查询看起来像:
SELECT
-- Columns
FROM TPMDBO.TPM_USERTASKS "Extent1"
INNER JOIN TPMDBO.TPM_TASK "Extent2" ON "Extent1".TASKID = "Extent2".TASKID
INNER JOIN TPMDBO.TPM_PROJECTVERSION "Extent3" ON "Extent2".PROJECTID = "Extent3".PROJECTID AND "Extent2".VERSIONID = "Extent3".VERSIONID
WHERE "Extent1".USERID = 5 and "Extent2".STAGEID > 0 and "Extent2".STAGEID <> 3 and "Extent3".STAGEID <= 10
上面的查询将在大约 1 秒内运行。通常,我可以JOIN
使用该Include
方法指定。但是,这似乎不适用于属性。换句话说,我不能这样做:
from t in user.TPM_TASK.Include("TPM_PROJECTVERSION")
有没有办法优化这个 LINQ 语句?我使用 .NET4 和 Oracle 作为后端数据库。
解决方案:
该解决方案基于 Kirk 在下面的建议,并且由于context.TPM_USERTASK
无法直接查询而有效:
var tasks = (from t in context.TPM_TASK.Include("TPM_PROJECTVERSION")
where t.TPM_USER.Any(y => y.USERID == UserId) &&
t.STAGEID > 0 && t.STAGEID != 3 && t.TPM_PROJECTVERSION.STAGEID <= 10
orderby t.DUEDATE, t.PROJECTID
select t);
它确实导致嵌套SELECT
而不是TPM_USERTASK
直接查询,但它似乎仍然相当有效。