【问题标题】:How to keep your Stored Procedures DRY in C#.NET?如何在 C#.NET 中保持存储过程 DRY?
【发布时间】:2008-11-08 05:45:55
【问题描述】:

我们对数据库的每个查询都使用存储过程。这似乎令人难以置信的un-DRY

  1. 设计表格
  2. 为该表设计 CRUD 操作 SP
  3. 设计代码(最好是一个类)来填充参数并执行 CRUD SPs

如果我们添加单个列或更改数据类型,我们必须在 .NET 中编辑表、少数 SP 和少数函数。

有什么技巧可以减少这种重复?

更新:

结合Vinko的想法,我找到了this。这是我为需要它的人想出的一些代码(用 C# 编写):

SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MySQLConnString"].ConnectionString);
SqlCommand comm = new SqlCommand("NameOfStoredProcedure", conn);
comm.CommandType = CommandType.StoredProcedure;

conn.Open();
SqlCommandBuilder.DeriveParameters(comm);
conn.Close();

foreach (SqlParameter param in comm.Parameters)
{ /* do stuff */ }

【问题讨论】:

标签: .net stored-procedures dry


【解决方案1】:

避免修改至少 SP 的一个技巧是编写它们以使用“自省”,即从内部表或 information_schema 视图中推断列名和数据类型。

编写的代码更复杂,但它可以避免每次表更改时都必须修改它,并且可以在其余的 SP 中重复使用。

创建一个将为您描述表的 SP,例如使用您将从其余 SP 调用的临时表(colname varchar,type varchar)。

顺便说一句,如果您的查询很复杂,这可能会变得非常复杂甚至不可行,但另一方面,如果不是,它可以为您省去很多麻烦。

【讨论】:

  • 我实际上是在开始这样的事情,但我正在努力寻找最好的方法。有什么想法/例子吗?
  • 我需要更多详细信息来了解您实际在做什么/如何分享一个有用的示例。但是您可以在 SO 上搜索信息架构,并了解如何查询它以获得您需要的一切,如果这是问题的话。
【解决方案2】:

我建议使用代码生成工具,例如 NetTiers 来生成您的 CRUD 层。

【讨论】:

  • 谷歌搜索名为“YAGNI”的反模式。
  • 这是对我的回答的回应吗?您介意详细说明吗?
  • 是的。实际上,并非每个表都需要所有四个操作。并非所有表格都可以通过相同的 C/R/U/D 模式进行充分处理。因此,您正在创建在许多情况下永远不会使用的代码(但无论如何都会成为支持负担的一部分。)
  • 如果你坚持使用代码生成器,那么这不是问题。这就是重点。
  • @dkretz,如果该代码永远不会被使用并且永远不会被调用,它怎么会成为支持负担的一部分,特别是在最有可能自动生成的代码中?
【解决方案3】:

OOP 设计原则适用于过程代码,而不是声明性代码。特别是,重用 SP 是非常有问题的。

基于 CRUD 生成器的 UI 设计很有名。另一种将用户明确转变为数据录入员的方法。如果您使用这些,请确保您在它们产生的内容和用户必须处理的内容之间有一个很好的抽象层。

如果我们添加单个列或更改数据类型,我们必须在 .NET 中编辑表、少数 SP 和少数函数。

听起来您的数据库设计决定了您的 OOP 要求。而是从另一个方向开始。

【讨论】:

    【解决方案4】:

    一旦 SQL 超出单个表,所有这些元查询方法都会死掉。或者想要一个计算列。或者……

    【讨论】:

    • 最好将其作为对您的评论目标的答案的评论。
    • 顺便说一句,我同意它很容易长毛。
    • 通常我会发表评论,但请注意,在这种情况下,我正在解决几个采用相同通用方法的响应...
    【解决方案5】:

    就我个人而言,我不太喜欢将查询代码放入存储过程中。除了高度复杂的东西,这似乎是多余的矫枉过正。

    这是我处理数据库和 crud 对象设计的方式:

    1. 我创建数据模型
    2. 我为每个表创建一个视图
    3. 我为每个表创建插入、更新和删除过程。
    4. 我所有的 C# 代码都指向视图和过程。

    这让我可以:

    1. 拥有高度灵活的查询目标(视图)
    2. 以任何我需要的方式查询视图,无需冗余。
    3. 防止通过数据库安全性直接访问表
    4. 如果我需要在不破坏代码的情况下重构底层数据模型(我知道,这可能会产生性能成本),请抽象数据模型

    拥有一个代表目标表的视图可能会处理许多查询,即使没有,最糟糕的情况是您需要专门为查询创建一个视图,这相当于为它,所以没有不利的一面。

    我听说有人建议使用存储过程来防止 SQL 注入攻击,但是如果您在查询视图时使用参数化查询,这无论如何都不是问题。 ...而且我们总是以任何方式使用参数化查询...对吗? ;-)

    【讨论】:

      【解决方案6】:

      您使用的“DeriveParameters”方法确实有效,但每个请求涉及 2 次数据库行程。这种方法会对性能产生影响。 Microsoft 的数据访问应用程序块 SqlHelper 类将通过执行完全相同的“自省”来缓解这种情况,但可以选择缓存参数以供重用。这将允许您创建单行 SP 调用,而无需重复“goo”设置参数等。

      http://msdn.microsoft.com/en-us/library/cc309504.aspx

      【讨论】:

        【解决方案7】:

        我不认为这真的属于 DRY 指南。这只是关于持久性,如果您手动执行#3,那么您应该考虑采用使这更容易的工具集之一。 LINQ to SQL 是我个人最喜欢的,但也有很多。

        您的 #2 也可以轻松实现自动化。减少 1)设计数据模型(在概念上)2)在持久层实现它(创建表或添加列)3)在应用程序级别使用它所需的整体工作。

        【讨论】:

          【解决方案8】:

          有些表没有 CRUD,不应该从您的应用程序中访问,并且是数据库实现模型的工件。特别是多对多链接表不应该被你的应用程序访问,它们应该由数据库通过存储过程来管理。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-03-07
            • 1970-01-01
            • 2011-06-06
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多