Как я могу объединить несколько выражений Select в Linq (в EF или SQL)? - PullRequest
3 голосов
/ 15 ноября 2010

Скажем, у меня есть эта модель вида:

public class SeriesLinkViewModel
{
    public static Expression<Func<Series, SeriesLinkViewModel>> FromSeries =
        s => new SeriesLinkViewModel
        {
            Name = s.Name,
            Slug = s.Slug,
        };

    public string Name { get; set; }
    public string Slug { get; set; }
}

Я вставил туда функцию проекции для удобства, так что теперь я могу сказать что-то вроде:

var links = dc.Series.Select(SeriesLinkViewModel.FromSeries);

Удивительно.Но что мне делать, если я хочу добавить к этому запросу?Скажем, я также хотел вытащить столбец Description из таблицы.Обычно я мог бы просто сделать select new { } и поместить туда Description, но я не могу этого сделать, потому что я могу поместить только одну проекционную функцию в `.Select ().

Я надеялсяЯ мог бы сделать что-то вроде этого:

q = from s in dc.Series
    select new
    {
        Series = SeriesLinkViewModel.FromSeries.Compile()(s),
        Description = s.Description
    };

Но я получил исключение:

System.InvalidCastException: Невозможно привести объект типа 'System.Linq.Expressions.FieldExpression'набрать 'System.Linq.Expressions.LambdaExpression'.

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

Ответы [ 4 ]

6 голосов
/ 15 ноября 2010

Решено с помощью LinqKit :

var fs = SeriesLinkViewModel.FromSeries; //needs to be local for some reason
q = from s in dc.Series.AsExpandable() //enables LinqKit to do its magic
    select new
    {
        Series = fs.Invoke(s), //and voila!
        Description = s.Description
    };
2 голосов
/ 12 мая 2012

Это дополнение к ответу Рей (который я пометил как правильный).Если вы хотите удалить зависимость от локальной переменной, взгляните на этот ответ Дана Абрамова о том, как исправить LinqKit .

0 голосов
/ 28 ноября 2017

На мой взгляд, это более удачное решение.

public class SeriesLinkViewModel
{
    public static Expression<Func<Series, SeriesLinkViewModel>> FromSeries =
        s => new SeriesLinkViewModel
        {
            Name = s.Name,
            Slug = s.Slug,
        };

    public string Name { get; set; }
    public string Slug { get; set; }
}

public class SeriesLinkExtendedViewModel: SeriesLinkViewModel
{
    public new static Expression<Func<Series, SeriesLinkExtendedViewModel>> FromSeries = 
        SeriesLinkViewModel.FromSeries.Merge(s => new SeriesLinkExtendedViewModel
        {
            Description = s.Description
        });

    public string Description { get; set; }
}

// Somewhere else...
var q = from s in dc.Series.Select(SeriesLinkExtendedViewModel.FromSeries);

Метод расширения «Слияние» возвращает проекцию, являющуюся результатом слияния обоих выражений проекции, и, таким образом, содержит три столбца: Имя, Слаги описание.

Фактическую реализацию можно найти по этой ссылке: https://coding.abel.nu/2013/01/merging-expression-trees-to-reuse-in-linq-queries/

0 голосов
/ 15 ноября 2010

Я знаю, что это не совсем то, что вы ищете, но один из возможных способов обойти это создать такой метод

private IQueryable<SeriesLinkViewModel> FromSeries(IQueryable<Series> seriesQuery)
{
    return from s in seriesQuery
           select new SeriesLinkViewModel
           {
                Name = s.Name,
                Slug = s.Slug
           };
}

Затем, когда вы захотите использовать проекцию, выполните запрос через нее.

return FromSeries(from s in Series
                  where s.Name == "foo"
                  select s);

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

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