C# 复杂linq编译查询

C# 复杂linq编译查询,c#,performance,linq,compiled-query,C#,Performance,Linq,Compiled Query,我试图弄明白如何将这样一个复杂的查询转换为编译后的查询,并保持代码干净。这个没有那么复杂,但它是一个例子,我有更复杂的查询 因此,我想转换这个预测查询: public List<GetAnswers> GetAnswers(int pQuestionId, string pSearch, int? pSkip, int? pTake, GetAnswersOrderBy pOrderBy, bool pOrderByIsAscending, out int pTot

我试图弄明白如何将这样一个复杂的查询转换为编译后的查询,并保持代码干净。这个没有那么复杂,但它是一个例子,我有更复杂的查询

因此,我想转换这个预测查询:

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 GetAnswers(int pQuestionId,string pSearch,int?pSkip,int?pTake,GetAnswersOrderBy pOrderBy,bool porderbyisasceding,out int pTotalNumberOfLines)
{
字符串搜索=pSearch.ToUpper().Replace(“,”);
string languageCode=Thread.CurrentThread.CurrentCulture.ToString().ToLower().Substring(0,2);
IQueryable query=this.Context.Set();
//通过问卷筛选问题
query=query.Where(w=>w.QuestionID==pQuestionId);
如果(!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(“,”)
。包含(搜索));
开关(pOrderBy)
{
case GetAnswersOrderBy.correct答案:
query=pOrderByIsAscending?query.OrderBy(w=>w.CorrectAnswer):query.OrderByDescending(w=>w.CorrectAnswer);
打破
案例GetAnswersOrderBy.ResponseCount:
query=pOrderByIsAscending?query.OrderBy(w=>w.ResponseCount):query.OrderByDescending(w=>w.ResponseCount);
打破
违约:
打破
}
pTotalNumberOfLines=query.Count();
var pagedQuery=query.Skip(pSkip±0)
.取(pTake??pTotalNumberOfLines);
var projectedQuery=pagedQuery.Select(s=>
新的
{
答案=s,
s、 答:,
AnswerTranslationLanguages=s.AnswerTranslations.Select(qt=>qt.Language),
}).ToList();
返回projectedQuery.Select(s=>newgetanswers()
{
Id=s.Answer.Id,
Label=s.Answer.Label,
CorrectAnswer=s.Answer.CorrectAnswer,
反馈=s.答案.反馈,
权重=s.答案
}).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;
}
public List GetAnswers(int pQuestionId,string pSearch,int?pSkip,int?pTake,GetAnswersOrderBy pOrderBy,bool porderbyisasceding,out int pTotalNumberOfLines)
{
var compiledQuery=CompiledGetAnswers(参数…);
var projectedQuery=compiledQuery.Select(s=>
新的
{
答案=s,
s、 答:,
AnswerTranslationLanguages=s.AnswerTranslations.Select(qt=>qt.Language),
}).ToList();
返回projectedQuery.Select(s=>newgetanswers()
{
Id=s.Answer.Id,
Label=s.Answer.Label,
CorrectAnswer=s.Answer.CorrectAnswer,
反馈=s.答案.反馈,
权重=s.答案
}).ToList();
} 
公共静态函数编译的etanswers(int pQuestionId、字符串pSearch、int?pSkip、int?pTake、GetAnswersOrderBy pOrderBy、bool porderbyisasceding、out int pTotalNumberOfLines)
{
字符串搜索=pSearch.ToUpper().Replace(“,”);
string languageCode=Thread.CurrentThread.CurrentCulture.ToString().ToLower().Substring(0,2);
IQueryable query=this.Context.Set();
//通过问卷筛选问题
query=query.Where(w=>w.QuestionID==pQuestionId);
如果(!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(“,”)
。包含(搜索));
开关(pOrderBy)
{
case GetAnswersOrderBy.correct答案:
query=pOrderByIsAscending?query.OrderBy(w=>w.CorrectAnswer):query.OrderByDescending(w=>w.CorrectAnswer);
打破
案例GetAnswersOrderBy.ResponseCount:
query=pOrderByIsAscending?query.OrderBy(w=>w.ResponseCount):query.OrderByDescending(w=>w.ResponseCount);
打破
违约:
打破
}
pTotalNumberOfLines=query.Count();
var pagedQuery=query.Skip(pSkip±0)
.取(pTake??pTotalNumberOfLines);
返回CompiledQuery(AppDbContext数据库,答案a)=>pagedQuery;
}

我想你所说的“干净”是指“更具可读性”。你真的在这么做。我的建议是将复杂的查询放入一个方法中,并给它一个有意义的名称

例如,如果人们不查看您的查询,他们就不会理解您在下面的代码中做什么

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))
    }
}
然后,您就能够使主方法变得清晰易读

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
}
public static Func CompiledGetAnswers(int pQuestionId,string pSearch,int?pSkip,int?pTake,GetAnswersOrderBy pOrderBy,bool porderbyisassending,out int pTotalNumberOfLines)
{
//做点什么
如果(!string.IsNullOrEmpty(pSearch))
query=query.SearchAnswersByLanguageCode(语言代码,搜索);
query=query.GetItOrdered(参数);
//做点什么
}

你已经差不多做到了。
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
}