65.9K
CodeProject 正在变化。 阅读更多。
Home

DBInspector - 论证代码生成

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.48/5 (13投票s)

2005年8月27日

15分钟阅读

viewsIcon

54164

DBInspector 是一款数据库开发者的瑞士军刀。DBInspector 帮助您根据数据库模式生成各种代码。

为代码生成据理力争

Mark Williamson

任何有一定能力的程序员都可以证明,编写代码来实现一个系统可能是一项冗余且艰巨的任务。我们经常会想,为什么我们必须一遍又一遍地编写几乎完全相同的代码,项目接项目。即使在我们编写程序代码时,我们也这样想。我们购买昂贵的集成开发环境,它们实际上只是一个巨大的记事本。这些出色的 IDE 允许我们开发和测试代码,甚至可能进行可视化设计,但很少能真正让我们的工作变得更容易。为了让我的工作更容易,一个工具基本上必须在我的命令下为我完成我的工作。

这就是代码生成工具的宗旨。在程序生产中采用 80/20 方法。不熟悉 80/20 法则?

DBInspector - Doin the dirty work for you!

帕累托法则 - 80/20 法则

1906 年,意大利经济学家维尔弗雷多·帕累托(Vilfredo Pareto)创建了一个数学公式来描述其国家财富分配不均的现象,他观察到 20% 的人拥有 80% 的财富。在 20 世纪 40 年代末,约瑟夫·M·朱兰博士(Dr. Joseph M. Juran)不准确地将 80/20 法则归因于帕累托,称之为帕累托法则。虽然可能名称有误,但帕累托法则,有时也称为帕累托定律,可以成为您有效管理的有力工具。

其来源

在帕累托做出观察并创建他的公式后,许多其他人也在各自的专业领域观察到类似的现象。质量管理先驱朱兰博士(Dr. Joseph Juran)在美国 20 世纪 30 年代和 40 年代工作时,认识到一个普遍的原则,他称之为“关键少数与次要多数”(vital few and trivial many),并将其记录下来。在一篇早期著作中,朱兰博士缺乏精确性,使得他似乎将帕累托关于经济学的观察应用于更广泛的工作。帕累托法则这个名字得以保留,可能是因为它听起来比朱兰法则更好。

因此,朱兰博士关于“关键少数与次要多数”的观察,即 20% 的事物总是负责 80% 的结果的原则,被称为帕累托法则或 80/20 法则。您可以在朱兰研究所(Juran Institute)一篇题为《朱兰的非帕累托法则》(Juran's Non-Pareto Principle)的文章中阅读他自己对这些事件的描述。

其含义

80/20 法则意味着在任何事物中,少数(20%)是关键的,而多数(80%)是琐碎的。在帕累托的案例中,这意味着 20% 的人拥有 80% 的财富。在朱兰的初步工作中,他确定了 20% 的缺陷导致 80% 的问题。项目经理知道 20% 的工作(最初的 10% 和最后的 10%)会消耗您 80% 的时间和资源。您可以将 80/20 法则应用于几乎任何事情,从管理科学到物理世界。

将 80/20 法则应用于编程

一个 80% 的例子

假设我们要创建一个网站。在当今的环境中,几乎没有人只想要一个静态网站,即纯 HTML。那会太容易了。当程序员介入时,我们就已经超越了网页设计师的领域,进入了动态内容的领域。这个术语暗示了一个数据库驱动的、交互式的、生动的、有生命力的软件应用程序。无论您的编程和项目开发方法是什么,它们都有以下共同点:

  • 需求收集
  • 数据库设计
  • 用户界面实现
  • 工作流程开发
  • 用户测试
  • 实现
  • 事后总结(维护、1.1 版本发布等)

在项目的每个阶段都有工具可以帮助我们交付项目。我最感兴趣、参与最多的领域是数据库设计、工作流程和用户界面开发。这些对我来说至少占用了我项目时间的 80%,这并非巧合。

进一步探讨我们的示例问题域,我们将从数据库设计开始。即使是最简单的系统也可能包含数十个数据库表。如果没有办法输入或检索数据,数据库将毫无价值。因此,我们还必须为我们的数据编程视图。这些视图可以是任何可想象的方法或样式,通常包括列出我们的数据,并允许我们编辑我们的数据。因此,我们可以假设,在大多数情况下,我们系统中的每个表都会有一个列表屏幕和一个编辑屏幕。

现在,将数据输入和输出我们的数据库系统需要一些其他的程序代码,这被称为数据访问层。有些人称之为业务对象、值对象、数据访问对象等。无论名称如何,其目的都是相同的:用代码表示我们的数据库。通常,每个表至少需要编写四种查询。这些被称为 CRUD,这个缩写代表创建、读取、更新、删除。

好的,让我们来回顾一下。

  • 每个表至少四种查询(或存储过程)
  • 每个表至少两种视图
  • 用于在代码中表示我们数据的业务对象

现在,如果我们数据库中有四个表,这将相当于

  • 16 个存储过程
  • 8 个视图
  • 8 个(最少)业务对象

我们甚至还没有开始讨论我们项目的“业务规则”,即我们系统的“如何”和“为什么”。你看,这就是那个可爱的 20%。

作为一名 Microsoft .NET 开发者,我可以告诉你,微软已经多次尝试使这方面对您来说更容易。然而,正如任何其他 .NET 开发者会告诉你的,实现这些仍然很麻烦,需要编写大量(有时是荒谬的)代码。上面的例子很容易产生 5000 多行代码。如果这是您一生中唯一要做的项目,那不算多。我知道,这不太可能。假设我们一年做一次这样的微型项目,一年就是 12 个项目乘以 5000 行代码。一年 60000 行代码。我在这里已经非常保守了……

无论您的编程方法如何,您最终都必须创建一些数据库表并编写一些代码。宇宙中没有工具可以为您省去这些。然而,市面上存在许多免费和商业工具,它们在大多数情况下都能为您提供帮助。此外,还有许多工具纯粹是垃圾,并且会阻碍您。

将上面的例子放到现实世界中,我个人从未写过一个只涉及四个表的应用程序。我曾在一个联系人管理系统上工作,该系统涉及 92 个数据库表,其中 9 个是连接表(并且没有相关的视图)。现在,让我们来计算一下。

我敢肯定地说,对于每一个平均大小的表,都至少有 2000 行相关的代码和存储过程。

92 x 2,000 = 184,000 行代码用于该 CMS 系统(而且这还是最低限度)

如果我们有一个工具可以检查我们的数据库模式,允许我们为字段、表、外键等创建一些额外的元数据,然后将此数据模型应用于各种模板,这些模板又可以输出我们能想象到的任何类型的文件,那会怎么样?

市面上有一些执行此目标的商业应用程序。其中一些相当不错。然而,我更喜欢编写软件,而不是购买软件。

没有万能药

代码生成不是万能药。它不会为您泡咖啡。有时您可能需要花费数小时来完善模板以生成代码。然后,您必须回到生成的代码中进行编辑,以提供最终的业务规则或不适用于整个项目的页面级别自定义。关于代码生成,基本上有两种对立的观点:

  • 生成代码的工具拥有它(不应编辑生成的代码)生成的代码是最终应用程序的起点

我属于第二类。而这正是 DBInspector 帮助我的地方。我生成数据网格、编辑表单、查询、存储过程等,这些都是高度冗余的代码,如果整天手工完成,会令人厌烦。然后,我获取这些代码,并进行最后的润色。

但是,请注意,让您的模板达到您喜欢的状态本身就是一项努力。但是,如果您在一个有现成的整体用户界面或编码标准的环境中工作,那么生成代码将是一个真正的省时利器。如果您在一个项目都不尽相同的环境中工作,您仍然会节省时间,但不要期望代码生成工具会为您创造奇迹。

隆重推出:DBInspector

在我编写联系人管理系统的时候,我真的、真的不想编写 92 x 4 个存储过程,更不用说大约 40 个可编辑的数据网格和带有验证等的编辑表单了。我是说,我真的、真的不想。所以我想,如果我用 XSL 来生成它们呢?我想我可以编写一个工具来从 Microsoft SQL Server 读取数据库模式,并在 XML 中创建一个该模式的模型。然后我就可以编写一些 XSLT 样式表来将其转换为代码。

这个解决方案在一段时间内效果很好,但与 XSL 搏斗几乎和编写存储过程一样令人沮丧和枯燥。最近,当我遇到 NVelocity 时,我重新审视了 DBInspector 程序。如果您是 Java 程序员,您可能听说过 Velocity。Velocity 是一个模板引擎,它可以内省某些对象并将它们的属性(字段)应用到模板,输出您能想到的任何有趣细节。

嗯,一位好心人将 Velocity 移植到了 .NET,我将这个包集成到了我的 DBInspector 工具中。Velocity 模板非常简单,但它们的实用性绝对值得称赞。通过简单的 if..else、foreach 和宏构造,我创建了一些非常强大的代码生成模板,而且我并不是 Velocity 模板的专家。

80/20 法则即使在代码生成工具上也继续适用。广泛接受的说法是,代码生成工具能帮助您完成 80% 的可用代码工作,但您仍然需要提供 20%。在某些情况下,这 20% 的工作量仍然很大,但至少我们可以专注于项目的业务规则,而不是仅仅成为一个编写数千行代码的代码猴子。

本文档的其余部分将向您展示我如何使用 DBInspector 来反向工程数据库,仅用一两个小时的时间(而且这已经是慷慨的了)生成数千行代码。

使用 DBInspector 开始项目的第一个步骤是创建数据库表。复习一下第三范式和关系数据库设计,这会对您有很大帮助!

虽然很难在此处表示,但上面的图是我门户项目的模式图,该模式图源自 Microsoft ASP.NET IBuySpy 门户入门套件。我的表比原始的多一些,但您可以看到有近二十多个表。还不错。我首先使用 DBInspector 为该数据库生成了存储过程。DBInspector 和类似工具的好处是,您的代码将保持一致。这意味着如果您在模板中犯了错误,至少您的错误是一致的!

在生成代码之前,让我们谈谈如何设计数据库以最大化代码生成成功率。

我可以说,并非所有数据库平台都生而平等。它们各有其存在的意义,并且必须和谐共存。话虽如此,我个人偏爱 Microsoft SQL Server。我发现它的工具比 Oracle 和 mySql 更易于使用,并且它拥有我能设想到的所有我需要的功能。在底层隐藏着一些非常棒的存储过程,它们能告诉您很多关于数据库的信息。具体来说,它们是:

sp_tables
sp_columns
sp_keys

它们都提供了大量关于数据库结构的信息。DBInspector 利用这些过程将数据库建模为其内部元数据形式,并最终将其写出为 XML。XML 仅用于维护您在 DBInspector 程序中所做的一些设置的状态。这些设置无法存储在数据库本身中,因此我们选择 XML 来帮助我们。

我们感兴趣的数据基本只有两类:

表和字段

是的,我们还使用关于数据库的其他信息,如主键和外键,但我们所需的大部分信息都在两类中:TableInfo 和 Field。

所以,我们有了数据库,现在我们想编写一些存储过程来输入数据并从中检索数据。我不会在这里讨论使用存储过程的原因,我只会说,如果您仍然用 SQL 语句来混乱您的代码,那就太糟糕了,太糟糕了!

这是 sp_tables 过程输出的屏幕截图

您可以看到它简单地列出了表及其类型。哦,多么无聊。是的,这是一个重要的开始。下一步是获取一些字段信息。我们使用 sp_columns 来完成。我将省去那些无聊的部分。现在,让我们进入 DBInspector。

加载程序后,会要求我们加载一个配置文件(有关此配置文件的详细信息请参见另一篇自述文件)。

加载后,DBInspector 会自动查询数据库并获取模式。这包括所有表、字段、主键和外键。它甚至会内省视图和存储过程,供那些好奇的人深入了解。

用户界面很简单,但功能充足。左侧的复选框列表用于选择和配置字段以包含在您的数据访问层中。在极少数情况下,我们会希望包含所有表。有些概念需要解释(稍后),所以请尽量跟上。

当我们点击字段时,我们会看到字段属性会发生变化。其中大部分仅供信息参考,但有三项值得讨论:

  • 搜索条件字段
    • 我们可以使用它来创建一个标志,以后可以用它来告诉我们的 Velocity 模板当前字段是否被标记为搜索条件的一部分。根据您的代码和实现,您可能会创建一个业务对象,用于向某些存储过程指定搜索条件。稍后将对此进行更多讨论。
  • 数据网格字段
    • 添加此功能是因为我需要一种方法来告诉我的 ASP.NET 数据网格生成模板,我希望该字段在网格中可见或不可见。我编写的模板仍然创建所有显示该字段的代码,但其可见性设置为 false。假设,您要做的就是将来在生成的 ASP.NET 代码中将值更改为 True,以使该字段在网格中可见。
  • 要显示的外键
    • 这是一个非常强大且方便的功能,值得进行深入解释。

使用外键

假设我们有两个表,分别称为 Customers 和 CustomerType。

有时,能够检索 Customers 表中的字段以及 CustomerType.Name 字段在同一个查询中会很方便。加载 DBInspector 并检查我们的示例数据库,我们可以根据应用程序的需求设置每个字段。下面显示了我们的 CustomerTypeID 外键字段。

通过在 Foreignkey Select Field 中选择Name,我们告诉 DBInspector 从 CustomerType.Name 字段中提取与我们相关的 Customers 记录的值。生成的业务对象和存储过程将包含一个名为 CustomerTypeIDName 的新字段,该字段包含此值。请注意,此字段不是底层 Customers 记录的一部分。因此,我们生成的类文件如下所示:

该字段由(也已生成)的存储过程填充。此方案有一个注意事项:如果您有一个可空的(nullable)外键关系,其中您的主表中的某些记录在外键表中没有匹配的记录,则不会返回任何结果。这实际上很容易克服,只需调整过程代码中的 JOIN 操作符即可。经过一些工作,我们可能可以优雅地处理这种情况(当然,这取决于数据库平台)。

一些生成的代码示例

正如您所见,代码是一致的。这是代码生成器的一个优点,代码总是保持一致。但是,如果您在模板中犯了错误,那么这个错误也是一致的 :)

我们用于生成存储过程的模板可能会非常复杂,但一旦您习惯了语法(以及 SharpDevelop 的语法高亮编辑器的帮助),就会变得简单。

鸣谢

DBInspector 实现了一些非常酷的开源项目,如果没有它们,它只是一个空壳。这也是 DBInspector 开源的原因。这些其他项目列在下面,并鼓励您查看它们:

这里有一些供您参考的优秀链接:

© . All rights reserved.