LINQ to Entities не распознает метод FromNews - PullRequest
0 голосов
/ 19 марта 2012

Сначала я объясню, что я пытаюсь сделать.

Я пытаюсь получить список новостных статей из моей структуры сущностей и преобразовать их в другой объект. Однако я получаю это исключение:

System.NotSupportedException: LINQ to Entities does not recognize the method 'Database.Entity.DataTransferObjects.NewsObject FromNews(Database.Entity.News)' method, and this method cannot be translated into a store expression.

Это мой код:

IEnumerable<NewsObject> news_articles = context.GetLatestNews(0);

    public IEnumerable<NewsObject> GetLatestNews(int start)
    {
        IQueryable<NewsObject> latest_news = context.News.Where(news => news.Published).Select(articles => NewsObject.FromNews(articles));
        IEnumerable<NewsObject> latest_news_ordered = latest_news.OrderByDescending(news => news.PublishedDate).Skip(start).Take(5);
        return latest_news_ordered;
    }

Это моя часть FromNews:

    public static NewsObject FromNews(News news)
    {
        return new NewsObject
        {
            Id = news.Id,
            Permalink = news.Permalink,
            Subject = news.Subject,
            Summary = news.Summary,
            Content = news.Content,
            Thumbnail = news.Thumbnail,
            Published = news.Published,
            PublishedDate = news.PublishedDate,
            PublishedBy = news.PublishedBy,
            CategoryId = news.CategoryId,
            Publisher = MemberObject.FromMember(news.Publisher),
            Category = CategoryObject.FromCategory(news.Category)
        };
    }

Я читал, что это проблема с тем, как построен / используется LINQ, но ни один из них не предоставил обходного пути для того, что я делаю. Я пытаюсь сделать код tiday:)!

Ответы [ 2 ]

2 голосов
/ 19 марта 2012

«LINQ to EF» работает с деревьями выражений. Код внутри запроса LINQ в действительности не выполняется, но анализируется и транслируется в SQL.

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

Один из способов - поставить ToList() перед Select. Таким образом, часть в Select больше не является «LINQ to EF», а LINQ to Objects, которая не имеет этих ограничений.
Но будьте осторожны: это также переместит вызовы в Skip и Take в LINQ to Objects и, следовательно, в память вашего приложения, что означает, что все объекты, соответствующие вашему предложению Where, извлекаются из базы данных, а не только 5 вы хотите вернуться.

Из-за всего этого я бы изменил запрос на:

return context.News.Where(news => news.Published)
              .OrderByDescending(news => news.PublishedDate)
              .Skip(start).Take(5)
              .ToList()
              .Select(articles => NewsObject.FromNews(articles))
              .ToList();

Обратите внимание на одну важную вещь: в этом коде есть два вызова ToList(). Первый - изменить код на LINQ to Objects, а второй - выполнить код в Select. Поскольку LINQ использует отложенное выполнение, часть Select будет выполняться каждый раз, когда вы перечисляете результат этого метода, каждый раз приводя к новым объектам.

1 голос
/ 19 марта 2012

Это должно работать, если вы сделаете это следующим образом:

public IEnumerable<NewsObject> GetLatestNews(int start)
{
    IQueryable<NewsObject> latest_news = context.News
        .Where(news => news.Published)
        .ToList()
        .Select(articles => NewsObject.FromNews(articles));
    IEnumerable<NewsObject> latest_news_ordered = latest_news
        .OrderByDescending(news => news.PublishedDate)
        .Skip(start).Take(5)
        .AsEnumerable();
    return latest_news_ordered;
}

Вызывая ToList () для вашего запроса, EF нажимает на базу данных и больше не строит деревья выражений в вашем iqueryable.После выполнения запроса он переходит к вашему методу FromNews.

Обновление

Чтобы разрешить отрывки из комментариев и пропустить их, можно сделать что-то вроде этого:

public IEnumerable<NewsObject> GetLatestNews(int start)
{
    IQueryable<NewsObject> latest_news = context.News
        .Where(news => news.Published)
        .OrderByDescending(news => news.PublishedDate)
        .Skip(start)
        .Take(5)
        .ToList()
        .Select(articles => NewsObject.FromNews(articles))
        .ToList(); // see Daniel Hilgarth's answer also
    IEnumerable<NewsObject> latest_news_ordered = latest_news
        .AsEnumerable();
    return latest_news_ordered;
}

Ответ на комментарий

Извините, я не осознавал, что вы переходите с IQueryable на IEnumerable.Вы можете сделать это, вызвав метод .AsEnumerable() в экземпляре IQueryable.Я обновил опубликованный код.

Я также обновил код для вызова .Skip и .Take до .OrderByDescending.Это имеет смысл, потому что если вы пропустите и возьмете перед заказом, ваши результаты будут упорядочены только в пределах 5 записей, которые вы берете.Нужно заказать, потом пропустить и взять.

Также см. Ответ Даниэля Хилгарта относительно отложенного выполнения по методу .Select.

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