复杂的linq编译查询

时间:2017-03-10 16:06:09

标签: c# performance linq compiled-query

我试图找出如何将这样的复杂查询转换为编译查询并保持代码清洁。这个并不复杂,但它的一个例子我有更复杂的查询。

所以我想转换这个预测的查询:

public List<GetAnswers> GetAnswers(int pQuestionId, string pSearch,   int?       pSkip, int? pTake, GetAnswersOrderBy pOrderBy, bool  pOrderByIsAscending, out int pTotalNumberOfLines)
{
    string search = pSearch.ToUpper().Replace(" ", "");
    string languageCode = Thread.CurrentThread.CurrentCulture.ToString().ToLower().Substring(0, 2);
    IQueryable<Answer> query = this.Context.Set<Answer>();
    //Filter question by questionnaire
    query = query.Where(w => w.QuestionID == pQuestionId);

    if (!string.IsNullOrEmpty(pSearch))
        query = query.Where(w => (w.AnswerTranslations.Any(a => languageCode == a.LanguageCode)
                         ? w.AnswerTranslations.FirstOrDefault(a => languageCode == a.LanguageCode).Label
                         : w.AnswerTranslations.OrderBy(o => o.Language.Priority).FirstOrDefault().Label)
                         .ToUpper().Replace(" ", "")
                         .Contains(search));
    switch (pOrderBy)
    {
        case GetAnswersOrderBy.CorrectAnswer:
            query = pOrderByIsAscending ? query.OrderBy(w => w.CorrectAnswer) : query.OrderByDescending(w => w.CorrectAnswer);
            break;
        case GetAnswersOrderBy.ResponseCount:
            query = pOrderByIsAscending ? query.OrderBy(w => w.ResponseCount) : query.OrderByDescending(w => w.ResponseCount);
            break;
        default:
            break;
    }
    pTotalNumberOfLines = query.Count();

    var pagedQuery = query.Skip(pSkip ?? 0)
                         .Take(pTake ?? pTotalNumberOfLines);
    var projectedQuery = pagedQuery.Select(s =>
        new
        {
            Answer = s,
            s.AnswerTranslations,
            AnswerTranslationsLanguages = s.AnswerTranslations.Select(qt => qt.Language),
        }).ToList();
    return projectedQuery.Select(s => new GetAnswers()
    {
        Id = s.Answer.Id,
        Label = s.Answer.Label,
        CorrectAnswer = s.Answer.CorrectAnswer,
        Feedback = s.Answer.Feedback,
        Weighting = s.Answer.Weighting
    }).ToList();
}

这样做是为了保持代码清洁:

public List<Answer> GetAnswers(int pQuestionId, string pSearch,   int?       pSkip, int? pTake, GetAnswersOrderBy pOrderBy, bool  pOrderByIsAscending, out int pTotalNumberOfLines)
{
    var compiledQuery = CompiledGetAnswers(params...);

    var projectedQuery = compiledQuery .Select(s =>
        new
        {
            Answer = s,
            s.AnswerTranslations,
            AnswerTranslationsLanguages = s.AnswerTranslations.Select(qt => qt.Language),
        }).ToList();

    return projectedQuery.Select(s => new GetAnswers()
    {
        Id = s.Answer.Id,
        Label = s.Answer.Label,
        CorrectAnswer = s.Answer.CorrectAnswer,
        Feedback = s.Answer.Feedback,
        Weighting = s.Answer.Weighting
    }).ToList();
} 

public static Func<AppDbContext, Answer, IQueryable<Answer>> CompiledGetAnswers(int pQuestionId, string pSearch,   int?       pSkip, int? pTake, GetAnswersOrderBy pOrderBy, bool  pOrderByIsAscending, out int pTotalNumberOfLines)
{
    string search = pSearch.ToUpper().Replace(" ", "");
    string languageCode = Thread.CurrentThread.CurrentCulture.ToString().ToLower().Substring(0, 2);
    IQueryable<Answer> query = this.Context.Set<Answer>();
    //Filter question by questionnaire
    query = query.Where(w => w.QuestionID == pQuestionId);

    if (!string.IsNullOrEmpty(pSearch))
        query = query.Where(w => (w.AnswerTranslations.Any(a => languageCode == a.LanguageCode)
                         ? w.AnswerTranslations.FirstOrDefault(a => languageCode == a.LanguageCode).Label
                         : w.AnswerTranslations.OrderBy(o => o.Language.Priority).FirstOrDefault().Label)
                         .ToUpper().Replace(" ", "")
                         .Contains(search));
    switch (pOrderBy)
    {
        case GetAnswersOrderBy.CorrectAnswer:
            query = pOrderByIsAscending ? query.OrderBy(w => w.CorrectAnswer) : query.OrderByDescending(w => w.CorrectAnswer);
            break;
        case GetAnswersOrderBy.ResponseCount:
            query = pOrderByIsAscending ? query.OrderBy(w => w.ResponseCount) : query.OrderByDescending(w => w.ResponseCount);
            break;
        default:
            break;
    }
    pTotalNumberOfLines = query.Count();

    var pagedQuery = query.Skip(pSkip ?? 0)
                         .Take(pTake ?? pTotalNumberOfLines);
    return CompiledQuery(AppDbContext db, Answer a) => pagedQuery;
}

1 个答案:

答案 0 :(得分:0)

我猜你干净的意思是“更具可读性”。你实际上是在做这件事。我的建议是将您的复杂查询放入一个方法中并给它一个有意义的名称。

例如,如果人们不查看您的查询,他们将无法理解您在以下代码中正在做什么

query = query.Where(w => (w.AnswerTranslations.Any(a => languageCode == a.LanguageCode)
                         ? w.AnswerTranslations.FirstOrDefault(a => languageCode == a.LanguageCode).Label
                         : w.AnswerTranslations.OrderBy(o => o.Language.Priority).FirstOrDefault().Label)
                         .ToUpper().Replace(" ", "")
                         .Contains(search));

您可以制作扩展类

public static class MyQueryExtension
{
    public static IQueryable<Answer> SearchAnswersByLanguageCode(this IQueryable<Answer> query, string languageCode, string search)
    { 
        return query.Where(w => (w.AnswerTranslations.Any(a => languageCode == a.LanguageCode)
                     ? w.AnswerTranslations.FirstOrDefault(a => languageCode == a.LanguageCode).Label
                     : w.AnswerTranslations.OrderBy(o => o.Language.Priority).FirstOrDefault().Label)
                     .ToUpper().Replace(" ", "")
                         .Contains(search))
    }
}

并在您的代码中调用它

query = query.SearchAnswersByLanguageCode(languageCode, search);

然后,您可以使主要方法清晰可读

public static Func<AppDbContext, Answer, IQueryable<Answer>> CompiledGetAnswers(int pQuestionId, string pSearch,   int?       pSkip, int? pTake, GetAnswersOrderBy pOrderBy, bool  pOrderByIsAscending, out int pTotalNumberOfLines)
{
    //Do something
    if (!string.IsNullOrEmpty(pSearch))
        query = query.SearchAnswersByLanguageCode(languageCode, search);

    query = query.GetItOrdered(parameters);

    //Do something
}