【问题标题】:SOLID stored procedures and functionsSOLID 存储过程和函数
【发布时间】:2013-09-12 09:55:21
【问题描述】:

我想在我正在使用的应用程序中开始更多地使用存储过程。该应用程序搜索十几个数据库。应用程序将信息存储在自己的数据库中。

我正在考虑将业务逻辑偏移到特定数据库中的存储过程。因此,如果逻辑对所有外部数据库都是通用的,则将其保存在应用程序 (.NET) 中。如果逻辑特定于数据库,则创建存储过程。

我不确定 SOLID 如何与存储过程和函数一起工作,因为没有接口或抽象。以下帖子似乎建议您尝试合并查询:http://ledgersmbdev.blogspot.co.uk/2013/02/building-solid-databases-interface.html。例如,如果一个存储过程有四个 SQL 语句,那么为什么不尝试将它们组合成一个 SQL 语句呢?这是帖子说的吗?这是一种可靠的方法吗?

【问题讨论】:

    标签: sql sql-server oop design-patterns stored-procedures


    【解决方案1】:

    我正在考虑将业务逻辑偏移到存储过程中 特定的数据库。因此,如果逻辑对所有外部 数据库然后将其保存在应用程序 (.NET) 中。如果逻辑是 特定于数据库,然后创建一个存储过程。

    这句话引起了我的极大关注。当您说逻辑是否特定于数据库时,我认为您的意思是上述十二个中的一个,这是一个设计缺陷。数据库就是这样,信息存储,它们不应该需要任何“特殊”逻辑来在暴露的任何视图结构之外访问它们。此外,如果需要以非设置方式操作数据,则需要将其放入应用程序中。也就是说,当它们可以抵消您的应用程序时,不要让您执行计算。

    在设计应用程序时,您必须确保不会将数据库变形以忽略关系模型。以我的经验,这是使您的应用程序难以管理且速度缓慢的最佳方法之一。澄清一下,业务逻辑不应该存在于数据库中,这使得其他人难以使用您的数据。反对这一点的典型论据是,“我是唯一使用数据的人”,我说这是一个糟糕的设计原因。

    接下来,您应该尝试确定在关系(集合)模型中实际有效的方法,并构建一个可以查询该数据的应用程序。而不是构建适合您的应用程序的数据库。话虽如此,SOLID 不适用于关系模型,因为它们不是面向对象的
    WIKI

    在计算机编程中,SOLID(单一职责、开闭、 Liskov 替换、接口隔离和依赖倒置) 是 Michael Feathers 为“第一 五个原则”,早期由 Robert C. Martin1[2] 2000s[3] 代表面向对象的五个基本原则 编程和设计。

    评论更新

    应用程序链接来自不同系统的信息并决定 何时可以删除一组记录(这些是通用规则 适用于所有系统)。然后有特定于数据库的规则 必须在删除前应用。我在考虑抵消 本地业务规则到存储过程。 ——

    查看此评论,我不完全了解在审计/软删除之外还有哪些特定于数据库的规则。我同意数据库特定规则可以设置为数据库中的管理存储过程,当您遇到以下问题时,您必须划清界限:

    我的应用程序查询历史数据,除非它早于6 months,否则必须从离线存储中检索它。

    6 months 之后删除此数据的选项是允许应用程序通过某些业务逻辑清除它,或者创建一个计划任务来执行此清理,因为它是删除元组的正常数据库操作。

    我的论点是将其放入数据库中并禁止您的应用程序调用这些过程。事实上,您的应用程序甚至不应该知道在正确抽象的应用程序中存在数据库。因此,如果这是您提出的示例,那么我的解决方案如下:

    1) Create stored procedures in the database that only a maintenance based user can invoke,   NOT THE APPLICATION  
    2) Create a database scheduled task to run these based on your data needs.  
    

    【讨论】:

    • 谢谢+1。外部数据库包含必须更新和有时删除的信息。每个数据库的规则都不同。该应用程序用于搜索目的,并在数据库中保存自己的信息。这会改变你的想法吗?
    • @w0051977 当你说更新/删除时你能澄清一下吗?你的意思是在你的应用程序中还是在外部?另外,应用程序如何知道要搜索什么?
    • 应用程序链接来自不同系统的信息并决定何时可以删除一组记录(这些是适用于所有系统的通用规则)。然后,在删除之前必须应用特定于数据库的规则。我正在考虑将本地业务规则偏移到存储过程。
    • 如果数据可以通过多种方式进入数据库,则业务逻辑必须存在于数据库中。诸如导入和报告之类的任何事情都无法通过应用程序进行,并且许多系统有多个应用程序访问它们,并且需要在任何地方强制执行一些业务规则,否则您将遇到数据完整性问题。诸如 FK 和列上的约束之类的东西都需要在数据库中。认为数据库只是数据存储的想法是有缺陷的,通常会导致不良数据。
    • 我读过你所说的,我不同意。作为一名数据库专家,正是这种态度造成了许多我被要求解决的问题。任何必须对所有数据都适用的规则必须是 inteh 数据库。任何认为应用程序足够的人都是短视的。
    【解决方案2】:

    我同意不将业务逻辑放入 SQL 的概念以及 SQL 作为基于集合的语言的概念。

    将 SOLID 视为一些非常好的编程实践的 OO 特定实现,并将它们应用于您编写的任何代码,包括 SQL。良好的表架构设计将包含 SOLID 理念。

    我花了太多时间调试大型复杂的存储过程,所以如果你能避免它,请这样做。如果您必须编写存储过程代码,那么 SOLID 可以帮助您。

    例如,我有一个大型存储过程,它查询几十个表并返回一个数据集供打印机使用以发送“欢迎信”。这是伪装成“报告”并用 SQL 编写的业务流程的经典示例。

    从 SOLID 镜头看这个操作:

    它应该有一个单一的责任和一个改变的理由。

    代码既决定了谁收到了一封信,也决定了该信中包含哪些数据。如果过程的任一方面发生变化,您必须更新并重新测试整个系统。一个可靠的原则是有一个函数来确定谁收到一封信以及信中的内容。

    这可以像使用单个查询返回客户列表一样简单。将其作为 ID 或 TVP 数组输入另一个存储过程以收集数据。

    打开/关闭

    在大多数 SP(存储过程)代码中,整个过程要么是硬编码的,要么是“数据驱动的”。数据驱动通常是针对这一原则的 SQL 努力。 SQL 流由 CASE 修改,该 CASE 将字段值或获得 EVAL 的文本字段中的 SQL 进行透视。

    在我们刚刚创建的“主”SP 中可以看到解决我的问题的可靠方法 现在我有一个调用 GET_CUSTOMERS 和另一个调用 GET_DATA 的 SP。这个 master 基本上控制着工作流程,并且该工作流程不应该改变。主站已关闭以进行修改。

    如果我们需要增强系统以发送电子邮件,并且电子邮件具有不同的数据字段,那么我可以将调用 GET_DATA 替换为调用 GET_DATA_FOR_EMAIL开放修改

    主人只有一个责任。如果工作流程发生变化,则此主节点会根据规则 #1 发生变化。

    里氏替换原则

    这很 OO,但是为了说明一点,我们假设 GET_CUSTOMERS SP 在这里可以被视为一个可替换的对象。我应该能够进行不同的查找,比如 GET_CUSTOMERS_WHO_NEED_DIFFERENT_LETTER 并且能够重用我的代码。或者可能是 GET_CUSTOMERS_FOR_INTERNAL_TEST?如果系统的所有组件都是一次性的且不可重复使用,那么系统将更难维护和理解。这可能是一个延伸。少考虑 OO 对象继承,多考虑可重用的具有相似参数的函数。

    依赖倒置原理

    这是我见过的最大的失败。不要围绕选择和 where 子句编写代码。我的系统以 *SELECT * FROM table, table, table where customers.letter-sent=false* 开始(实际上超过 1k 行)我希望以 找到所有客户并向他们发送一封信结束.从抽象和代码开始,最高级别控制 SP 中的工作流。

    这个想法是抽象是“寻找客户”并返回客户列表。我应该能够将该逻辑交换为代码中的其他内容。我经常看到的违规行为是让“查找客户”写入连接到客户表上的表,然后另一个 SP 读取该表。在这种情况下,您的抽象会泄漏到实现中,并且您从可重用代码变成了为特定表发送信件的系统。

    SQL 非常强大,很容易将抽象中应该分开的步骤组合到实现中。

    存储过程是一个很好的工具,可以帮助团队以可读性换取性能,并以牺牲可伸缩性为代价带来便利。它仍然是代码,从其他语言中窃取模式只会在您的整体设计中有所帮助。

    如果您需要一个简单的设计模式,您通常不需要设计模式。如果您的代码超过 50 行左右,请尝试将其移至应用层和/或考虑进行可靠的重构。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-15
      • 1970-01-01
      • 1970-01-01
      • 2017-04-23
      • 1970-01-01
      • 2011-12-05
      • 2012-11-20
      • 2023-03-22
      相关资源
      最近更新 更多