Miro
Miro

Reputation: 1806

Single statement query

I have this code:

var questionCategory = questionnaire.QuestionCategories
    .First(x => x.Type == (int)questionCategoryType);
return questionCategory.Questions.Select(x => new 
    {
       Id = x.Id,
       Text = x.Text,
    });

I'm interested if there is a way of shortening this into one statement, i.e. avoid making variable questionCategory . I'm looking for Extesion method or LINQ solution, or little bit of both :) .

Upvotes: 1

Views: 75

Answers (5)

usr
usr

Reputation: 171218

Using First forces the query to be executed (the same goes for enumerating navigation properties like questionnaire.QuestionCategories). This is to be avoided in order to not issue multiple queries.

return from qc in dataContext.QuestionCategories
       where qc.QuestionaireID == questionnaire.ID //guessing names here
       where qc.Type == (int)questionCategoryType
       from q in qc.Questions
       select new 
    {
       Id = q.Id,
       Text = q.Text,
    };

This will issue a single query, remoting all work to the SQL Server.

Upvotes: 0

cuongle
cuongle

Reputation: 75316

With this way, needless to check null on QuestionCategories, the final result is to Select on Questions, so you don't need to use First, instead, use Where:

return questionnaire.QuestionCategories 
     .Where(x => x.Type == (int)questionCategoryType) 
     .SelectMany(c => c.Questions.Select(q => new
                                        {
                                            Id = q.Id,
                                            Text = q.Text
                                        }));

Upvotes: 1

Ufuk Hacıoğulları
Ufuk Hacıoğulları

Reputation: 38478

I suggest using FirstOrDefault instead of First so you don't get an InvalidOperationException when sequence is empty or none of the elements match your predicate.

Also you should check for null after the first query and provide a default value for that situation. This is not what you asked for but it's more defensive.

var questionCategory = questionnaire.QuestionCategories.FirstOrDefault(x => x.Type == (int)questionCategoryType);

return questionCategory != null
        ? questionCategory.Questions.Select(x => new 
                                                 {
                                                    Id = x.Id,
                                                    Text = x.Text,
                                                 })
        : someDefaultValue;                                                 

Upvotes: 1

Garrett Fogerlie
Garrett Fogerlie

Reputation: 4458

return questionnaire.QuestionCategories.First(x => x.Type == (int)questionCategoryType)
            .Questions.Select(x => new { Id = x.Id, Text = x.Text, });

of if you would like to return null if x.Type == (int)questionCategoryType is not found:

return questionnaire.QuestionCategories.FirstOrDefault(x => x.Type == (int)questionCategoryType)
            .Questions.Select(x => new { Id = x.Id, Text = x.Text, });

Upvotes: 0

Alex Kalicki
Alex Kalicki

Reputation: 1533

Might not be the nicest way to do it, but you could easily simplify your code to one line with no variable storage like so:

return questionnaire.QuestionCategories.First(x => x.Type == (int)questionCategoryType)
                    .Questions.Select(x => new {Id = x.Id, Text = x.Text});

Upvotes: 1

Related Questions