Mik*_*sen 5 .net c# sql linq entity-framework
我有以下代码,这是行为不端:
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);
Run Code Online (Sandbox Code Playgroud)
第一行,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
Run Code Online (Sandbox Code Playgroud)
对于具有大量任务的用户,此查询大约需要18秒.我希望WHERE子句也包含STAGEID过滤器,这将删除大多数行.
接下来,它似乎为TPM_PROJECTVERSION上面列表中的每对执行一个新查询:
SELECT
-- Columns
FROM TPMDBO.TPM_PROJECTVERSION "Extent1"
WHERE ("Extent1".PROJECTID = :EntityKeyValue1) AND ("Extent1".VERSIONID = :EntityKeyValue2)
Run Code Online (Sandbox Code Playgroud)
即使这个查询很快,如果用户在一大堆项目中有任务,它也会执行几百次.
我想生成的查询看起来像:
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
Run Code Online (Sandbox Code Playgroud)
上面的查询将在大约1秒内运行.通常,我可以指定JOIN使用该Include方法.但是,这似乎不适用于属性.换句话说,我做不到:
from t in user.TPM_TASK.Include("TPM_PROJECTVERSION")
Run Code Online (Sandbox Code Playgroud)
有没有办法优化这个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);
Run Code Online (Sandbox Code Playgroud)
它确实导致嵌套SELECT而不是TPM_USERTASK直接查询,但它似乎相当有效.
是的,您正在下拉特定用户,然后引用关系TPM_TASK。它正在取消附加到该用户的每个任务,这正是它应该做的事情。当您这样做时,没有 ORM SQL 转换。您正在获取一个用户,然后将他的所有任务放入内存中,然后执行一些客户端过滤。这一切都是使用延迟加载完成的,因此 SQL 的效率会非常低,因为它无法批量处理任何内容。
相反,重写您的查询以直接TPM_TASK针对用户进行过滤:
var tasks = (from t in context.TPM_TASK
where t.USERID == user.UserId && t.STAGEID > 0 && t.STAGEID != 3 && t.TPM_PROJECTVERSION.STAGEID <= 10
orderby t.DUEDATE, t.PROJECTID
select t);
Run Code Online (Sandbox Code Playgroud)
请注意我们如何检查t.USERID == user.UserId。这产生了相同的效果,user.TPM_TASK但现在所有繁重的工作都是由数据库而不是在内存中完成的。
| 归档时间: |
|
| 查看次数: |
2250 次 |
| 最近记录: |