在使用Dapper时,SQL语句应该放在哪里?

26

我在工作中的mvc3项目中使用了dapper,并且很喜欢它。然而,当使用dapper时,应该如何分层应用程序呢?目前我只是将所有的sql直接放在控制器中( slap ),但我正在考虑创建一个具有静态字符串的类。这样我就可以做到


var reports = Dapper.Query<Report>(conn, MySql.ReportsRunningQuery)

当使用Dapper时,你如何存储你的SQL语句?


这可能是一个带有静态字符串的类,而不是枚举类型? - Marc Gravell
好的。是的。糟糕的早晨想法... - Christian Wattengård
3个回答

33

我建议将 SQL 语句放在你本来会放 LINQ 查询或 DataContext.ExecuteQuery 的地方。至于具体在哪里放... 呃,这取决于你需要多少分离。

然而,就个人而言,我认为把 SQL 隐藏在与 Query<T> 调用不相关的单独类中是没有好处的 - 你希望在上下文中看到它们,以便可以轻松验证数据(以及参数)。你也可能在现场构建查询(仍然是参数化的)。但对于常规的静态查询,除非有 很好的理由 需要将其抽象化,否则我会把 TSQL 作为文字直接保留在代码附近。

var reports = conn.Query<Report>(@"
select x.blah, y.blah
from x (snip)
where x.ParentId = @parentId and y.Region = @region", new {parentId, region});

(注意上述中的替代扩展方法的用法)

在我看来,上面的关键是你几乎不可能从任何其他地方重新使用那个查询 - 逻辑应该放在一个方法中,并从多个地方调用该方法。因此,隐藏查询查询背后的唯一其他原因是如果需要支持不同的数据库提供程序(具有不同的SQL语言版本)。而这种情况比人们想象的要少。


1
@Christian - 确保你有 using Dapper; 的命令。 - Marc Gravell
1
谢谢。但是如果把所有的SQL都放在控制器中,那不就成了“肥控制器”吗?而且根据不同的人的看法,这不是一个好的做法吗? - Christian Wattengård
7
如果你选择在控制器中进行数据访问,那么争论 TSQL 存放位置就无关紧要了——数据访问仍然存在。“肥胖”是关于它的功能而非行数计数的。 - Marc Gravell
@Robert - SP-free的一个非常吸引人的优点是部署简单;而且可以灵活地使用SQL,无需在SQL内部进行SQL生成(用于sp_executesql),但任何选择都可以是有效的。 - Marc Gravell
1
@Robert 没问题;很乐意考虑任何被记录为功能建议的事项。我们已经根据社区的建议添加了许多功能——其中一些现在在内部使用,一些则不是。 - Marc Gravell
显示剩余6条评论

12

使用资源文件对我们非常有用。我们在名为/Sql的文件夹中创建.sql文件,并将它们拖到SqlResource对象的“文件”部分中。资源文件的“字符串”部分非常干净,适合较小的SQL片段(例如我们可能正在查询的函数)。

因此,我们的SQL看起来像:

var reports = conn.Query<Report>(SqlResource.Blahs_get, new {parentId, region});

这样可以保持存储库的干净整洁。将所有SQL放入资源文件中还有其他好处,您可以遍历条目并可能使用PARSEONLY查询数据库,以确保如果数据库对象更改,您的查询会中断(请注意,这主要但不完全可靠)。

因此,总之,对我们而言,资源文件使事情变得真正干净整洁,但根据Marc Gravell的观点,它们不适用于生产代码内的可重用性……每个SQL语句只应由应用程序中的一个点使用。


非常好的解决方案,适用于那些一次性查询(例如报告等)。我一直在寻找这个,从未听说过资源文件。不再尝试在一个巨大的字符串中搞定查询了。 - CJ Edgerton

6
尽管这个问题现在已经相当古老了,但我想进一步建议将 SQL 存储到外部。Visual Studio(至少2015+版本)支持语法高亮显示、小型调试器和连接管理器,可用于*.sql文件。这些文件可以被标记为嵌入式资源并完全包含在程序集中,但与您的代码分开。您会讨厌看到非语法验证字符串中嵌入无色 SQL。
我已经在我的最近所有项目中采用了这种模式,结合像Dapper这样的 ORM,C# 和 SQL 之间的接口变得非常简化。我在GitHub 上有一个扩展 Dapper 的开源项目,其中提供了示例以及 NuGet 包。它还包括一个胡子启发的字符串替换引擎,有助于将脚本模板化以使其可重用或插入动态过滤条件。

我不记得它是否在那个具体的项目中。但是最终我使用了.SQL文件和一个T4生成器,生成了一个静态字符串常量类。这样我就可以通过SQL.Filename在我的代码中的任何位置获取查询。 - Christian Wattengård
啊,这是一个聪明的方法;并且可以在不进行任何修改的情况下与Dapper(或其他任何东西)集成。我唯一不太喜欢的部分是在我的开发过程中依赖外部工具,但我想把它放在构建事件中会自动化这个过程。感谢您的跟进和额外的建议。 - Null511
由于我是Visual Studio用户,T4处理已经集成在IDE中。我可能只需检查生成的.cs文件。因此,在这种情况下,不需要额外的构建步骤。 - Christian Wattengård

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接