Как передать переменные в Expression Func Projection перед компиляцией - PullRequest
1 голос
/ 03 июня 2019

Я пытаюсь написать функции выражения для моих проекций. Я нашел хорошую статью об этой ссылке . Но я не мог понять, как я могу передать переменные в эти функции.

Как я могу написать функцию проекции для этого

int i = 3;
var query = await _db.Users
                .FilterByName(name)
                .Select(item => new SearchResultItemViewModel
                {
                    Id = item.Id,
                    Article = item.FirstName + i.ToString()
                });
}))

Этот работает. В строке выбора SQL есть только Id и Firstname, но я не могу передать переменную.

   var query = await _db.Users
                .FilterByName(name)
                .Select(item => SearchResultItemViewModel.Projection)
public static Expression<Func<ApplicationUser, SearchResultItemViewModel>> Projection
        {
            get
            {
                return item => new SearchResultItemViewModel
                {
                    Id = item.Id,
                    Article = item.FirstName
                };
            }
        }

Этот работает, только если вы вызываете compile и вызываете. Строка SQL имеет все строки. Приводит к плохой производительности

   var query = await _db.Users
                .FilterByName(name)
                .Select(item => SearchResultItemViewModel.Projection.Compile().Invoke(item,i))
public static Expression<Func<ApplicationUser,int, SearchResultItemViewModel>> Projection
        {
            get
            {
                return( item,i) => new SearchResultItemViewModel
                {
                    Id = item.Id,
                    Article = item.FirstName + i.ToString()
                };
            }
        }

1 Ответ

2 голосов
/ 03 июня 2019

Я не использую EF, так что это может отличаться в вашем конкретном случае использования, но, похоже, это вопрос о выражениях LINQ больше, чем что-либо еще.

Первая большая проблема заключается в том, что вы пытаетесьиспользуйте Expression<Func<ApplicationUser, int, SearchResultItemViewModel>> там, где вы действительно имели в виду Expression<Func<ApplicationUser, SearchResultItemViewModel>>, и это не будет делать то, что вы хотите.Вместо привязки к переменной вы вызываете индексированный вариант Select.Поэтому вместо получения одинакового значения i для всех строк вы получите индекс строки.

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

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

С другой стороны, ваш код выше создает новый экземпляр каждый раз, когда вы обращаетесь к свойству Projection.Так почему бы просто не изменить его на функцию и сгенерировать нужное вам выражение, когда вам это нужно?

public static Expression<Func<ApplicationUser, SearchResultItemViewModel>> Projection(int parm)
    => item => new SearchResultItemViewModel
        {
            Id = item.Id,
            Article = item.FirstName + parm.ToString()
        };

Каждый раз, когда вы вызываете метод, вы получаете выражение, которое использует указанное значение.

Или вы могли бы использовать посетитель выражения, чтобы взять шаблонное выражение и изменить константы в нем так, как вам нужно в данный момент.Забавно, но я думаю, что это немного выходит за рамки.

...