ASP MVC:服务应该返回 IQueryable 的吗?

Posted

技术标签:

【中文标题】ASP MVC:服务应该返回 IQueryable 的吗?【英文标题】:ASP MVC: Should services return IQueryable's? 【发布时间】:2011-01-13 23:26:39 【问题描述】:

你怎么看?您的 DAO 是否应该返回一个 IQueryable 以在您的控制器中使用它?

【问题讨论】:

【参考方案1】:

没有。您的控制器根本不应该处理任何复杂的逻辑。保持苗条;模型(不是 DAO)应该把它需要传递给视图的所有东西交给控制器。

在 Controller 类中看到查询(甚至可查询)我认为是代码异味。

【讨论】:

谢谢亚伦,很好。尽管如此,使用 IQueryable 还是有一些优势,例如服务的灵活性和可维护性——因为使用管道和过滤器模式,DAO 接口的增长会减少。你怎么看? 意大利面条式代码总是似乎在项目年轻且规模较小时更易于维护;但是,随着项目的发展,您会开始后悔没有明确分离关注点。 传递您的 IQueryable 和/或使用管道和过滤器并不等于意大利面条代码。意大利面条代码通常与语言或技术无关。 @jfar:控制器类的职责是根据用户请求提供视图。除了意大利面条代码之外,在IQueryable 周围踢球或对数据库有任何了解如何?它完全打破了领域模型提供的封装。 (你确实有一个领域模型,对吧?) 不,我有一个持久性模型。如果我的回答中两种操作方法 sn-ps 之间的区别是一种“干净”而另一种是意大利面条,那么您对意大利面条代码的标准非常低。【参考方案2】:

目前听起来很有吸引力,但是really isn't。

【讨论】:

【参考方案3】:

我喜欢将 IQueryable 传递给我的控制器,因为在我的应用开发的整个生命周期中,我不必在每个 DAO 方法和接口中创建蹩脚的分页和排序方法。

GetCustomersByLastname( string lastname )

迅速变成

GetCustomersByLastname( string lastname, string sortcolumn, int pagesize, int page )

一次又一次,一次又一次。擦!

使用 IQueryable,您可以以正交方式实现分页和排序,例如利用 IPagedList 项目。返回 IQueryable 还可以让您轻松访问总对象 .Count() ,而不会对您的数据层产生更多反常。

@Robert 的 IQueryable 等于胖控制器的参数非常不稳定。 Fat 控制器类似于过去臃肿的 .aspx.cs 页面。如果您所做的只是连接到您的 DAL,然后将结果从您的查询技术中获得“肥胖”,那么您可以通过在单个类中塞入大量逻辑来获得它。除非您开始在内部滚动日志记录、通知和其他正交关注点,否则您不会因为您的数据访问方法而获得胖控制器。

public ActionResult Detail( string searchTerm )

    var model = MyDAL.MyObjects( searchTerm );

对比:

public ActionResult Detail( string searchTerm )

    var model = MyDAL.MyObjects.Where( x => x.Name == searchTerm );

我看不出有什么明显的区别。

@Mark Seemann 的回答同样不稳定。当然,您可以在项目中间更改整个数据层,但无论您多么抽象,这都将是一场复杂的灾难。他使用的示例是从 Linq2Sql 切换到 Windows Azure 的表存储。 RDBMS 到键/值存储?痛点是您的存储库实施?从 RDBMS 到 Key/Value 存储将是一些疯狂的事情,无论如何这将是可怕的。

Mark 在他的论点中还提到了领域驱动设计。那是您建筑的系统类型吗?是否有足够的“领域”而不是纯粹的 CRUD 场景使这种方法有价值?如果不是那么为什么要打扰?

无论如何,使用 LINQ 和 IQueryable 接口可以减少切换数据层的痛苦。如果您在支持 LINQ 和 IQueryableProvider(我认为这就是名称)的 ORM 之间切换,那么只有下游代码才关心该更改。您的控制器将保持与现在市场上大多数 ORM 之间的相同切换。

【讨论】:

如果这样做的目的是排序和分页,那么这可以通过包装IQueryable<T> 但仍输出域模型的IPager<T> 接口轻松完成。我使用这种方法,它只需要很少的代码,并且消除了控制器和数据库之间的任何直接交互。你的比较很奇怪;似乎您的项目缺少域模型,在这种情况下,当然没有太大区别 - 但如果您没有域模型,那么您实际上没有 MVC。 另外请注意,使用IQueryable<T> 完成的任何分页(我猜这是OrderBySkip 的组合)将是低效的。虽然使用它可能更方便,但有效的分页通常需要使用原始 SQL 或存储过程,它们都不适合 IQueryable<T> 过滤器/投影。 @Aaronaught 您的第二条评论是错误的。所有启用 Linq 的.Net ORMS 使用 .Skip() 和 .Take() 从 IQueryable 生成高效的分页 sql。 我不是也从来不是 DDD、MDD、TDD 或本月最新的敏捷风格的倡导者;但是,我确实相信独立于关系模型的领域模型在几乎任何应用程序中都是很好的设计。过去有几次我跳过那个阶段并通过高级抽象公开数据对象,后来我后悔了这个决定。只是我的两分钱。 :) @Aaronaught 您的寻呼问题非常关注 YAGNI。这篇文章读起来很好,我学到了很多,但性能统计数据并不令人印象深刻。没有人会翻阅 100k 记录表。用户将搜索某些内容。这是“如果你有数以亿计的用户和数千兆字节的数据怎么办”论点的变体,这是大多数系统所没有的。我尊重您的意见,但您的编码似乎与您的域将很丰富并且您的规模将很大的假设背道而驰。 *** 是用“贫血模型”构建的,它似乎工作正常。 ;)【参考方案4】:

如果您遵循“胖模型,瘦控制器”范式,那么就不会。

在Fat Controller anti-pattern 上查看此帖子。

【讨论】:

以上是关于ASP MVC:服务应该返回 IQueryable 的吗?的主要内容,如果未能解决你的问题,请参考以下文章

MVC / LINQ /合并Iqueryable对象[关闭]

服务层是不是应该返回 MVC 应用程序的视图模型?

asp.net mvc中使用linq to sql查询数据集(IQueryable类型) 怎么用foreach循环去数据集的数据?

我应该通过 ASP.NET MVC 操作还是 WCF 公开 Web 方法?

ASP.NET MVC 服务层输入输出数据

ToArrayAsync() 抛出“源 IQueryable 未实现 IAsyncEnumerable”