【问题标题】:Converting a COMPLEX stored procedure into C# & ADO.Net将 COMPLEX 存储过程转换为 C# 和 ADO.Net
【发布时间】:2013-03-08 23:02:29
【问题描述】:

这不是关于 SP 是好是坏的问题。或者用 C# 写 SQL 语句是好是坏。

很快我们就开始着手一个新项目,这是一个典型的库存/计费管理系统。这将使用 .Net 和 C# 作为语言进行开发。数据库尚未最终确定。

在此应用程序中不允许使用存储过程,它将具有中等到复杂的数据库操作。因此,我可以使用 SP 轻松编写的逻辑,现在我必须使用 C# 和 ADO.Net 编写。

现在采用一个非常假设的用例,其中客户选择了 5 件商品并准备在柜台生成账单……。这通常具有以下数据库操作:

  • 检查 INVENTORY 表以查看是否所有 5 个订单项都可用(数量充足)。
  • 如果任何项目不可用 - 从账单中删除项目并更新 BILL 表
  • INVENTORY 表的数量字段将被更新,数量字段将扣除已售出的商品。
  • 提醒/更新其他表是某个项目的阈值数量低于某个点。

现在看看这个场景,这一切都可以在 SP 中轻松完成。这包含很多查询、IF 条件、可能的循环等,看起来像是 SP 的一个很好的竞争者。 我想从专家那里得到的是:

  1. 是否有在 C# 和 ADO.Net 中编写此类代码的最佳实践。在 C# 中,我们通常可以使用 ADO.Net 重新创建相同的代码……。但这是唯一的方法还是正确的方法?
  2. 我读过很多人说存储过程很糟糕……。但是在考虑这样的复杂场景时……您不觉得存储过程更适合这种情况吗?

【问题讨论】:

  • 嗨 Yuvi,我建议您的 ADO.net 是指实体框架/LINQ2SQL 之类的东西?为什么要创建一个难以维护的地狱查询?为什么不创建多个查询创建一个事务?
  • @Jordy van Eijk,我并不是说所有这些都将使用大查询创建。我要说的是,这将导致在 C# 中使用 if 条件和可能的循环进行大量查询。所以我的问题是在 C# 和 ADO.Net(或实体框架)中这样做的最佳实践是什么?
  • 存储的 Proc 是有用的脚本,用于管理数据库、修改、批处理、帮助进行复杂查询(您的应用程序应该从一开始就避免这样做)像 shell 脚本(bash , ksh, PowerShell..) 可以做 for-loop, if.. 和很多事情。但是我们只用它们来管理操作系统,几乎没有用它们来构建软件。 IMO,数据访问层的“正确方法”是将复杂查询分解为许多小查询与缓存解决方案(redis,内存数据库..)相结合。如今,材料很便宜,可测试、可行和高质量的应用却很昂贵。

标签: c# stored-procedures ado.net


【解决方案1】:

是否有在 C# 和 ADO.Net 中编写此类代码的最佳实践。在 C# 中,我们通常可以使用 ADO.Net 重新创建相同的代码……。但这是唯一的方法还是正确的方法?

所以我认为根据您的问题,您会更乐意使用Dapper 之类的东西来访问数据库。如果您不知道,Dapper 是一个非常轻量级的数据库访问库,它甚至支持一些更复杂的需求(例如在一次往返中返回多个结果集,然后将这些结果反序列化为 POCO 类)。

简而言之,使用 Dapper,您可以灵活地完全按照自己的意愿查询数据库,而且速度快得离谱。

现在,举个更具体的例子,Dapper 扩展了IDbConnection 接口,所以你选择什么数据库并不重要:

数据库尚未最终确定。

它很容易参数化,因此不受SQL Injection的约束:

var parms = new { ID = 1, Bar1 = "Hello" };
var foo = connection.Query<Foo>(
    "SELECT Bar1, Bar2 FROM Foo WHERE ID = @ID AND Bar1 = @Bar1",
    parms);

并且它支持事务,因此您仍然可以将操作作为单个事务进行管理:

var tran = connection.BeginTransaction();
var parms = new { ID = 1, Bar1 = "Hello" };
var foo = connection.Query<Foo>(
    "SELECT Bar1, Bar2 FROM Foo WHERE ID = @ID AND Bar1 = @Bar1",
    parms, tran);

老实说,虽然实体框架确实越来越流行,而且微软正在向他们投入 资金,但在使用 Dapper 后我不再购买它们。这就是为什么。一般来说,最好利用数据库来做它最擅长的事情,而 Dapper 允许这样做,它所做的只是为您提供一种机制,您可以通过该机制大幅减少从 ADO.NET 中的数据库获取数据并对其执行所需的样板代码。

现在,这是进入存储过程参数的好方法。

我读过很多人说存储过程不好......。但是当考虑这样一个复杂的场景时……你不觉得存储过程更适合这种情况吗?

存储过程还不错。大多数人说这可能来自以下两个角度之一:

  1. 他们只是在跟风。
  2. 他们不知道存储过程的目的和好处。 请注意:我没有说愚蠢,我说的是ignorant

尽管人们普遍认为,存储过程具有很好的用途。首先,编译执行计划。其次,它们很容易参数化以更快地进行更复杂和多级的查询 - 而视图和直接 SQL 则不是。 第三,DBA 更容易保护它们。

我有一个查询,它是一个直接的 SQL 查询,因为我当时工作的公司也有同样的想法,并且我通过将其设为存储过程将其性能提高了 98%。 这为公司每月节省了 2,000 美元他们准备购买的额外硬件!

正如我之前所说的,将数据库用于它擅长的领域。我认为这经常会丢失,因为我看到很多人试图对 500,000 个对象使用C# 和 .NET 框架,他们无法弄清楚为什么它不够快 - 他们应该在数据库服务器上对它们进行排序!这是一回事,它是 真的擅长!

不要让人们把你引向技术无用和糟糕的道路,因为很多人会告诉你触发器是糟糕的,但如果使用正确的理由,它们是完美的!

【讨论】:

  • 迈克尔,感谢您的全面解释。我将检查 Dapper。我认为它会符合要求。我还对在单次往返中返回多个结果集然后将这些结果反序列化为 POCO 类的功能感兴趣。这也恢复了我对良好的旧存储过程的信念:)
  • “我通过将其设置为存储过程将其性能提高了 98%”,您是否使用 SQL Server Profiler 来监控其性能准确性或 StopWatch 类?
  • @user1451111 在那种情况下,我利用了 SQL Profiler 和处理期间创建的自定义指标的组合。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-10
  • 1970-01-01
  • 2014-03-23
  • 2021-12-12
  • 2010-10-23
  • 2013-06-18
  • 1970-01-01
相关资源
最近更新 更多