C# 我可以让Linq到EF更高效吗?
我有一个设计,我们存储给定用户对脚本问题的答案。 一个脚本可以有许多问题,每个问题可以由给定的用户回答多次 MS SQL表的外观(删除额外的详细信息)或多或少类似于:C# 我可以让Linq到EF更高效吗?,c#,sql,entity-framework,linq-to-sql,linq-to-entities,C#,Sql,Entity Framework,Linq To Sql,Linq To Entities,我有一个设计,我们存储给定用户对脚本问题的答案。 一个脚本可以有许多问题,每个问题可以由给定的用户回答多次 MS SQL表的外观(删除额外的详细信息)或多或少类似于: -Scripts ScriptId int (PK, identity) -ScriptQuestions ScriptId int (PK) QuestionId int (PK) -Questions QuestionId int (PK, identity) QuestionText varchar -Answ
-Scripts
ScriptId int (PK, identity)
-ScriptQuestions
ScriptId int (PK)
QuestionId int (PK)
-Questions
QuestionId int (PK, identity)
QuestionText varchar
-Answers
AnswerId int (PK, identity)
QuestionId int
UserId int
AnswerText varchar
我想为给定的脚本和给定的用户查询此数据库,并获取所有问题以及为每个问题(如果有)提供的最后答案。
在T-SQL中,我会这样做:
SELECT
sq.QuestionId,
q.QuestionText,
la.AnswerText
FROM
ScriptQuestions sq
ON s.ScriptId = sq.ScriptId
INNER JOIN Questions q
ON sq.QuestionId = q.QuestionId
LEFT OUTER JOIN (
SELECT
QuestionId,
AnswerText
FROM Answers
WHERE AnswerId IN (
SELECT
MAX(AnswerId) LastAnswerId
FROM Answers
WHERE UserId = @userId
GROUP BY QuestionId
)
) la
ON q.QuestionId = la.QuestionId
WHERE
sq.ScriptId = @scriptId
(未经测试,但我认为这与我会做的很接近)
我正在MVC 3应用程序上使用LinqToEF,为了获得我使用的结果:
var questions = from sq in script.ScriptQuestions
select new QuestionsAnswers
{
QuestionId = sq.QuestionId,
QuestionText = sq.Question.QuestionText,
LastAnswer = sq.Question.Answers
.Where(a => a.UserId == userId)
.OrderByDescending(a => a.AnswerId)
.Select(a => a.AnswerText)
.FirstOrDefault()
};
我确实得到了相同的结果,但当我从VS 2010运行Intellitrace profiler时,我可以看到linq将此转换为对脚本上的每个问题发送一条SELECT
语句,然后对每个答案发送另一条SELECT
语句。因此,如果脚本有20个问题,它将至少查询数据库40次,而不是像上面那样只发送一条SQL语句
我试图改变我创建LinqToEF语句的方式,但我无法克服nSELECT
语句的问题
这不可能是正确的方法,是吗 我猜您的查询使用LINQ to内存中的对象并延迟加载导航属性,因为您的查询以
script.ScriptQuestions
开始,它显然不是IQueryable
。因此,集合在内存中迭代,对于每个条目,您都可以访问sq.Question
和sq.Question.Answers
导航属性。如果每次访问这些属性时都启用了延迟加载,则会向数据库发出一个新查询以填充属性。您对sq.Question.Answers
集合的筛选将在完整集合的内存中执行
您可以尝试通过以下方式进行更改:
var questions = from sq in context.ScriptQuestions
where sq.ScriptId == script.ScriptId
select new QuestionsAnswers
{
QuestionId = sq.QuestionId,
QuestionText = sq.Question.QuestionText,
LastAnswer = sq.Question.Answers
.Where(a => a.UserId == userId)
.OrderByDescending(a => a.AnswerId)
.Select(a => a.AnswerText)
.FirstOrDefault()
};
这应该只是一个数据库查询,因为现在它是LINQ到具有
IQueryable
的实体,我想我更愿意在查询中将这些表连接在一起<代码>来自脚本中的sq。Sqriptquestions加入脚本中的a。a.questionid上的答案等于sq.questionid,其中userId==a.userId选择新建。。{}。(不完全是这个想法)。Linq将在没有额外内部查询的情况下过滤掉(实际上,在scriptQuestions中,每个项目只运行一次)。是的!你搞定了。现在好多了,它甚至使用外部应用程序来提高性能。谢谢。