Как я могу выделить предложения в параметризованном выражении? - PullRequest
1 голос
/ 29 апреля 2011

Привет всем.Я пытаюсь оптимизировать вызов Linq to Entities путем статического кэширования и повторного использования скомпилированного запроса.Запрос проверяет то же самое для переменного числа аргументов фильтра, и единственный способ скомпилировать аргументы запроса подобным образом - это явно использовать несколько аргументов (а не некоторую логику типа Contains ()), что в SQL не может бытьпараметризовано).

Это прекрасно работает и дает мне значительное повышение производительности.Проблема в том, что код ужасен.Я повторяю один и тот же кусок кода несколько раз для каждого из возможных параметров.Т.е.:

           Expression<Func<Entities, string, string, string, string, IQueryable<Instrument>>> query = 
(context, searchTerm0, searchTerm1, searchTerm2, searchTerm3) =>
                context.Instruments
                    .Where(
                        (searchTerm0 == null ||
                            instr.FullName.IndexOf(searchTerm0) > -1 ||
                            instr.ShortName.IndexOf(searchTerm0) > -1 ||
                            instr.Strategies.OrderBy(st => st.Level).Select(st => st.Name).Take(2).Any(strat => strat.IndexOf(searchTerm0) > -1))
                        &&
                        (searchTerm1 == null ||
                            instr.FullName.IndexOf(searchTerm1) > -1 ||
                            instr.ShortName.IndexOf(searchTerm1) > -1 ||
                            instr.Strategies.OrderBy(st => st.Level).Select(st => st.Name).Take(2).Any(strat => strat.IndexOf(searchTerm1) > -1))
                        &&
                        (searchTerm2 == null ||
                            instr.FullName.IndexOf(searchTerm2) > -1 ||
                            instr.ShortName.IndexOf(searchTerm2) > -1 ||
                            instr.Strategies.OrderBy(st => st.Level).Select(st => st.Name).Take(2).Any(strat => strat.IndexOf(searchTerm2) > -1))
                        &&
                        (searchTerm3 == null ||
                            instr.FullName.IndexOf(searchTerm3) > -1 ||
                            instr.ShortName.IndexOf(searchTerm3) > -1 ||
                            instr.Strategies.OrderBy(st => st.Level).Select(st => st.Name).Take(2).Any(strat => strat.IndexOf(searchTerm3) > -1))
                .Take(50);

Я думал, что смогу реорганизовать это, динамически создавая выражения фильтра, но это кажется невозможным.Я хочу сделать что-то вроде этого:

    var filterExpression = (instr, searchTerm) =>
        searchTerm == null ||
        instr.FullName.IndexOf(searchTerm) > -1 ||
        instr.ShortName.IndexOf(searchTerm) > -1 ||
        instr.Strategies.OrderBy(st => st.Level).Select(st => st.Name).Take(2).Any(strat => strat.IndexOf(searchTerm) > -1);

    Expression<Func<Entities, string, string, string, string, IQueryable<Instrument>>> query = (context, searchTerm0, searchTerm1, searchTerm2, searchTerm3) =>
        context.Instruments
            .Where(i => filterExpression(i, searchTerm0))
            .Where(i => filterExpression(i, searchTerm1))
            .Where(i => filterExpression(i, searchTerm2))
            .Where(i => filterExpression(i, searchTerm3))
        .Take(50);

Но, конечно, это не скомпилируется, потому что filterExpression является выражением и не может быть вызвано таким образом (и это не может быть просто Func, потому чтоLinq to Entities не сможет распознать его как переводимый метод)жестко закодированы и использованы повторно.То есть это не параметризованный запрос.

Я застрял, выписывая все для каждого термина?Я бы хотел поддержать максимум 14. Можно ли выделить предложения, которые принимают параметры таким образом?

1 Ответ

1 голос
/ 29 апреля 2011

Выезд Predicate Builder .Документы довольно хорошие.

Я использовал его для поддержки десятков предикатов, и результирующий код мал, когда хорошо продуман.

...