我在工作中将 dapper 用于 mvc3 项目,我喜欢它。但是,在使用 dapper 时,您应该如何对应用程序进行分层?目前我只是将我所有的 sql 都直接填充到控制器中(slap),但我正在考虑用静态字符串创建一个类。所以我可以做
var reports = Dapper.Query<Report>(conn, MySql.ReportsRunningQuery)
使用 dapper 时如何存储 sql?
我在工作中将 dapper 用于 mvc3 项目,我喜欢它。但是,在使用 dapper 时,您应该如何对应用程序进行分层?目前我只是将我所有的 sql 都直接填充到控制器中(slap),但我正在考虑用静态字符串创建一个类。所以我可以做
var reports = Dapper.Query<Report>(conn, MySql.ReportsRunningQuery)
使用 dapper 时如何存储 sql?
我会说将 sql 放在您将放置等效 LINQ 查询的位置,或者将 sql 放在 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});
(还要注意上面的替代扩展方法用法)
IMO,上面的关键是您极不可能从任何其他地方重用该查询- 逻辑将被放入一个方法中,并且从多个地方调用该方法。因此,您可能用来将查询隐藏在中央包装器后面的唯一其他原因是您是否需要支持不同的数据库提供程序(使用不同的 SQL 方言)。这比人们想象的要少。
使用资源文件对我们非常有用。我们在文件夹调用 /Sql 中创建 .sql 文件并将它们拖到 SqlResource 对象的“文件”部分。资源文件的“字符串”部分对于较小的 sql 片段(例如我们可能正在查询的函数)来说非常干净和容易。
所以,我们的 sql 看起来像:
var reports = conn.Query<Report>(SqlResource.Blahs_get, new {parentId, region});
这样可以保持存储库真正干净。将所有 sql 都放在资源文件中还有其他好处,因为您可以遍历条目并可能使用 PARSEONLY 查询 db,以确保如果 db 对象发生更改,您的查询会中断(请注意,这主要是但不是100% 可靠)。
所以,总而言之,对我们来说,资源文件让事情变得真正干净,但在 Marc Gravell 看来,它们并不是为了生产代码中的可重用性……每个 sql 语句只能在您的应用程序中使用一个点。
虽然这个问题现在已经相当老了,但我想进一步建议 SQL 的外部存储。Visual Studio(至少 2015+)具有语法高亮,以及用于 *.sql 文件的小型调试器和连接管理器。这些文件可以进一步标记为Embedded Resource并完全包含在程序集中,但与您的代码分开。你会越来越讨厌看到嵌入在未经语法验证的字符串中的无色 SQL。
我在最近的所有项目中都采用了这种模式,并结合了像Dapper这样的 ORM ,C# 和 SQL 之间的接口变得非常少。我在GitHub 上有一个扩展 Dapper 的开源项目,它可以提供示例以及NuGet 包。它还包括一个受小胡子启发的字符串替换引擎,这对于模板化脚本以使其可重用或插入动态过滤条件很有用。