Условно игнорируйте поля с помощью LINQ select - PullRequest
0 голосов
/ 11 марта 2020

Мне не удалось найти ни одного примера, где можно условно исключить поля на основе переменной в проекции выбора в LINQ, см. Также LINQ: выбрать объект и изменить некоторые свойства, не создавая новый объект .

Позвольте мне рассказать о том, чего я пытаюсь достичь. Я хочу ограничить некоторые поля в DTO, которые устанавливаются из модели на основе того, может ли пользователь редактировать данные (например, поле комментария). Например, следующий вариант выбора с делегатом с именем CustomerView.

var qry = _ctx.Customer.Select(CustomerView(User.IsInRole("Editor")));

Модель Customer имеет свойство навигации Orders, а следующая функция преобразует данные в DTO CusomerViewModel.

private Expression<Func<Customer, CustomerViewModel>> CustomerView(bool isEditor) {
    return c => new CustomerViewModel
    {
        Id = c.Id,
        Name = c.Name,
        Comment = isEditor ? c.Comment : null,
        OrderCount = c.Orders.Count()
    };
}

Это сгенерирует SQL, как и CASE WHEN @__isEditor_0 = TRUE THEN Comment ELSE NULL, который работает, но я бы предпочел, чтобы выражение даже не генерировалось, то есть поле осталось по умолчанию. Это простой случай использования, но если бы я хотел сделать то же самое с полем OrderCount, подзапрос SQL все равно был бы включен.

Конечно, я мог бы создать еще одну функцию для пользователей, не являющихся редакторами, которая исключает некоторые поля, но я бы предпочел не иметь отдельных прогнозов для обслуживания, особенно когда они более сложные.

Я вижу вопросы, где Dynami c LINQ используется для предложений where, но не так много для select. Реален ли этот подход?

Редактировать : Есть ли способ вручную удалить поля из дерева выражений после выбора, возможно, с помощью метода расширения?

1 Ответ

0 голосов
/ 12 марта 2020

Используя LINQKit Мне удалось достичь желаемого результата, добавив AsExpandable() для выбора.

var qry = _ctx.Customer.AsExpandable().Select(CustomerView(User.IsInRole("Editor")));

Затем добавив выражение для поля комментария и вызов Invoke() в полевом назначении.

private Expression<Func<Customer, CustomerViewModel>> CustomerView(bool isEditor) {
    Expression<Func<Customer, string>> exprComment;
    if (isEditor)
        exprComment = c => c.Comment;
    else
        exprComment = c => null;

    return c => new CustomerViewModel
    {
        Id = c.Id,
        Name = c.Name,
        Comment = exprComment.Invoke(c),
        OrderCount = c.Orders.Count()
    };
}

Кажется, это работает, но мне все равно было бы интересно услышать о любых альтернативных подходах.

...