C# 我可以让Linq到EF更高效吗?

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

我有一个设计,我们存储给定用户对脚本问题的答案。 一个脚本可以有许多问题,每个问题可以由给定的用户回答多次

MS SQL表的外观(删除额外的详细信息)或多或少类似于:

-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语句的方式,但我无法克服n
SELECT
语句的问题


这不可能是正确的方法,是吗

我猜您的查询使用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中,每个项目只运行一次)。是的!你搞定了。现在好多了,它甚至使用外部应用程序来提高性能。谢谢。