Используйте опциональное предложение OR в Linq.Table.Where () - PullRequest
2 голосов
/ 26 октября 2009

Есть ли способ сделать проверку ProjectID ниже части необязательного блока? Я недавно конвертировал .Net из Java EE и ищу что-то похожее на Hibernate Criteria API. Я хотел бы упростить блок ниже и должен вызывать Where () только один раз. Я также не уверен в последствиях для производительности выполнения Where () с лямбдами, поскольку я только начал работать с .Net неделю назад.

public IQueryable<Project> FindByIdOrDescription(string search)
    {
        int projectID;
        bool isID = int.TryParse(search, out projectID);

        IQueryable<Project> projects;

        if (isID)
        {
            projects = dataContext.Projects.Where(p => p.ProjectDescription.Contains(search) || p.ProjectID == projectID);
        }
        else
        {
            projects = dataContext.Projects.Where(p => p.ProjectDescription.Contains(search));
        }

        return projects;
    }

Ответы [ 3 ]

3 голосов
/ 26 октября 2009

Если вы ищете опционально добавление AND xyz, вы можете просто связать Where звонки:

var projects = dataContext.Projects.Where(p => p.ProjectDescription.Contains(search));
if (isID)
    projects = projects.Where(p => p.ProjectID == projectID);

К сожалению, все не так просто, когда вы хотите сделать OR xyz. Чтобы это работало, вам нужно будет вручную создать выражение предиката. Это не красиво. Один из способов сделать это -

Expression<Func<Project, bool>> predicate = p => p.ProjectDescription.Contains(search);
if (isID)
{
    ParameterExpression param = expr.Body.Parameters[0];
    predicate = Expression.Lambda<Func<Project, bool>>(
        Expression.Or(
            expr.Body,
            Expression.Equal(
                Expression.Property(param, "ProjectID"),
                Expression.Constant(projectID))),
        param);
}
var projects = dataContext.Projects.Where(predicate);

Обратите внимание, что добавление условия в существующий предикат - это намного больше, чем создание исходного выражения, потому что нам нужно полностью перестроить выражение. (Предикат должен всегда использовать один параметр; объявление двух выражений с использованием лямбда-синтаксиса создаст два отдельных объекта выражения параметра, по одному для каждого предиката.) Обратите внимание, что компилятор C # делает примерно то же самое за кадром, когда вы используете лямбда-синтаксис для исходного предикат.

Обратите внимание, что это может показаться знакомым, если вы привыкли к API-интерфейсу критериев для Hibernate, просто немного подробнее.


Обратите внимание, однако, что некоторые реализации LINQ довольно умны, поэтому может также работать следующее:

var projects = dataContext.Projects.Where(
    p => p.ProjectDescription.Contains(search)
      || (isID && p.ProjectID == projectID));

YMMV, однако, проверьте сгенерированный SQL.

1 голос
/ 26 октября 2009

Запрос не анализируется и не выполняется до тех пор, пока вы в первый раз не получите доступ к элементам IQueryable. Следовательно, независимо от того, сколько вы добавляете (куда вы вообще не добавляете), вам не нужно беспокоиться о слишком частом попадании в БД.

0 голосов
/ 26 октября 2009

Делегаты / выражения могут быть «связаны», например, (непроверенный псевдокод):

Expression<Predicate<Project>> predicate = p => p.ProjectDescription.Contains(search);
if ( isID ) 
    predicate = p => predicate(p) || p.ProjectID == projectId;

return dataContext.Where(predicate);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...