为什么这个LINQ表达式打破了我的循环&;转换逻辑

本文关键字:amp 循环 转换 我的 LINQ 表达式 为什么 | 更新日期: 2023-09-27 18:21:30

背景

ArticleService是一个为前端层提供方法的类,以便于与后端进行业务。

它的两个基本职责是在持久化数据时将ViewModels(ArticleViewModel)转换为适当的Model(Article),反之,在获取数据时将Models转换为ViewModels。。。我经常创建一个构建ViewModel对象的私有方法:

private ArticleViewModel BuildViewModel(Article a)
{
    return new ArticleViewModel { Title = a.Title /* all properties */ }
}

接下来,ArticleService提供了一种从数据存储中获取所有文章的方法,并将它们作为ViewModels:public IEnumerable<ArticleViewModel> All() 返回

调用类这样使用它:var articleViewModels = _articleService.All();

很简单,对吧?

问题:

我最初用一个经典的foreach循环懒散地写All()

private IEnumerable<ArticleViewModel> All()
{
    var viewModels = new List<ArticleViewModel>();
    foreach (var article in _db.Articles)
        viewModels.Add(BuildViewModel(article));
    return viewModels;
}

它工作得很好——articleViewModels是所有视图模型的实例化列表。

接下来,为了性能和美观,我使用ReSharper将这个循环转换为LINQ语句,然后将赋值语句和返回语句组合在一起。结果:

private IEnumerable<ArticleViewModel> All()
{
    return _db.Articles.Select(article => BuildViewModel(article)).ToList();
}

我调试了LINQ语句,野兽苏醒了:

LINQ to Entities不识别方法"ArticleViewModel"BuildViewModel(Article)"和此方法无法转换为存储表达式。

问题-为什么这个LINQ语句破坏了我的代码

注意:回到显式声明、赋值、返回与LINQ语句一起工作,所以我几乎可以肯定这与lambda逻辑有关

为什么这个LINQ表达式打破了我的循环&;转换逻辑

问题-为什么这个LINQ语句破坏了我的代码?

因为LINQ to Entities正试图将BuildViewModel转换为SQL。它不知道怎么回事,所以死得很惨。

在原始版本中,您将实体从数据库流式传输到本地框,然后使用BuildViewModel客户端进行投影。没关系。

所以我几乎可以肯定这与lambda逻辑有关。

没有。这是因为LINQ to Entities无法将BuildViewModel转换为SQL。是否使用lambda表达式来表达投影并不重要。

你可以这样重写代码:

return _db.Articles.
          .AsEnumerable()
          .Select(article => BuildViewModel(article)).ToList();

这导致_db.Articles被视为一个普通的旧可枚举对象,然后是投影客户端。现在LINQ to Entities不必弄清楚如何处理BuildViewModel

Jason的回答解释了错误,但没有列出简单的修复方法(如果您仍然想使用LINQ)。只需在"_db.Articles"之后添加对.AsEnumerable()的调用。这将强制使用LINQ to Objects(在内存中)执行任何未来的LINQ语句,而不是尝试使用IQueryable对数据库执行语句。

简单地说,函数BuildViewModel不可转换为原始SQL。也就是说