7

示例案例:

我们正在使用 SQL Server 构建租赁服务。有关可以租用的物品的信息存储在一个表中。每个项目都有一个状态,可以是“可用”、“出租”或“损坏”。不同的状态驻留在查找表中。

项目状态表:

id 名称
1 '可用'
2 '租用'
3 '损坏'

除此之外,我们还有一条业务规则,该规则规定,无论何时归还物品,它的状态都会从“已出租”更改为“可用”。
这可以通过像“update Items set state=1 where id=@itemid”这样的更新语句来完成。在应用程序代码中,我们可能有一个映射到 ItemState id:s 的枚举。但是,这些包含硬编码的值,可能会导致以后出现维护问题。假设开发人员要更改状态集但忘记修复相关的业务逻辑层......

有什么好的方法或替代设计来处理这类设计问题?
除了直接答案外,还感谢相关文章的链接。

4

10 回答 10

6

以我的经验,这是您实际上必须进行硬编码的情况,最好使用整数值与查找表的 id 匹配的 Enum。说“1”总是“可用”等等,我看不出有什么不对。

于 2009-10-30T15:01:13.737 回答
4

我见过的大多数系统都对查找表值进行硬编码并使用它。这是因为,在实践中,代码表很少像您想象的那样变化。如果它们确实发生了变化,您通常需要重新编译任何依赖该 DDL 的程序。

也就是说,如果您想让代码可维护(一个值得称赞的目标),最好的方法是将值外部化到属性文件中。然后,您可以稍后编辑此文件,而无需重新编码整个应用程序。

这里的限制因素是您的应用程序的内部状态取决于您从查找表中获得的值,因此这意味着一定程度的耦合。

对于应用程序不依赖该代码的查找例如,如果您的代码表存储了用于地址下拉列表的两字母状态代码列表),那么您可以将代码延迟加载到对象中并仅在需要时访问它们。但这对你正在做的事情不起作用。

于 2009-10-30T15:04:02.797 回答
2

当您在代码中定义了查找表和枚举时,您总是会遇到保持它们同步的问题。这里没有什么可以做的。两者都有效地生活在两个不同的世界中,并且通常彼此不了解。

您可能希望拒绝使用查找表,而只让您的业务逻辑操作这些值。在这种情况下,您会错过依靠参照完整性来支持数据完整性的选项。

另一种选择是以您在代码中永远不需要这些值的方式构建您的应用程序。这意味着将部分业务逻辑移动到数据库层,也就是将它们放入存储过程和触发器中。这也将具有对客户不可知论的好处。任何人都可以调用 SP 并确保数据将保持在一致性状态,并与您的业务逻辑规则保持一致。

于 2009-10-30T15:00:41.650 回答
1

您需要有一些永远不会改变的预定义值,无论是整数、字符串还是其他东西。

在您的情况下,状态的数值是状态的代理PRIMARY KEY项,在设计良好的数据库中永远不应该改变。

如果您担心一致性,请使用CHAR代码ARB.

但是,您应该坚持使用它以及数字代码,以便A始终表示Available等。

您的数据库结构和代码都应该记录在案。

于 2009-10-30T15:00:52.117 回答
1

我认为这是一个常见问题,也是一个值得关注的问题,这就是为什么我首先在​​谷歌上搜索并找到了这篇文章。

如果创建一个公共静态类来保存所有查找值,而不是硬编码,我们会在加载应用程序时初始化这些值并使用名称来引用它们呢?

在我的应用程序中,我们尝试了这个,它奏效了。您还可以进行一些检查,例如,代码中查找的不同可能值的数量应该与 db 中的相同,如果不是,则为 log/email/etc。但我不想为 40 多个商业实体的状态手动编码。

此外,这可能是更大的 OR 映射问题的一部分。我们暴露了太多持久层的细节,因此我们必须照顾它。使用 Entity Framework 之类的技术,我们无需担心“同步”部分,因为它是自动化的,对吗?

谢谢!

于 2010-03-18T15:56:49.317 回答
1

答案完全取决于您使用的语言:Java、PHP、Smalltalk 甚至汇编程序中的解决方案都不相同......

但是让我告诉你一些事情:虽然硬编码值确实不是一件好事,但有时你确实需要它们。而这几乎就是其中之一:您需要在代码中声明您当前对业务逻辑的了解,其中包括这些硬编码状态

因此,在这种特殊情况下,我会对这些值进行硬编码。

于 2009-10-30T15:02:43.940 回答
1

不要过度设计它。在尝试提出解决此问题的方法之前,您需要弄清楚这是否是一个问题。你能想到任何合法的假设场景,你会改变 itemState 表中的值吗?不仅仅是“如果有人更改了这张桌子怎么办?” 但是“有人出于Y原因想以X方式更改此表,这会产生什么影响?”。你需要保持现实。

新州?您添加一行,但不会影响现有行。删除状态?无论如何,您必须在代码中删除对它的引用。改变状态的ID?没有正当理由这样做。更改州名?没有正当理由这样做。

所以真的没有理由担心这个。但是,如果您必须在非理性的人随机决定将可用更改为 2 因为它更适合他们的风水的情况下进行干净的维护,请确保所有表格都是通过从配置文件中读取这些值的脚本生成的,并且然后确保所有代码都从同一个配置文件中读取常量。然后您有一个定义位置,并且任何时候您想要更改您修改该配置文件而不是 DB/代码的值。

于 2009-10-30T15:23:18.797 回答
0

我使用了与您所描述的类似的方法 - 数据库中的一个表,其中包含值和描述(用于报告等)和代码中的枚举。我已经用代码中的注释处理了同步,上面写着“这些值取自数据库 ABC 中的表 X”,以便程序员知道需要更新数据库。为了防止在没有相应代码更改的情况下从数据库端进行更改,我在表上设置了权限,以便只有某些人(希望他们记得他们也需要更改代码)才能访问。

于 2009-10-30T15:03:38.897 回答
0

这些值必须是硬编码的,这实际上意味着它们不能在数据库中更改,这意味着将它们存储在数据库中是多余的。

因此,对它们进行硬编码,并且在数据库中没有查找表。而是将项目状态直接存储在项目表中。

于 2011-02-23T04:20:35.447 回答
0

您可以构建您的数据库,以便您的应用程序实际上不必关心代码本身,而是关心它们背后的业务规则。

我做了以下两项:

  1. IsAvailable您的一个或多个代码是否具有应用程序关心的特定特征,例如?如果是这样,请将其作为标志列添加到代码表中,其中匹配的设置为true(或您的数据库的等效项),不匹配的设置为false.
  2. 您是否需要在特定条件下使用特定的单一代码?您可以创建一个名为 的单例表,EnvironmentSettings其中的列ItemStateIdOnReturn是表的外键ItemState

如果我想避免在应用程序中声明枚举,我将使用 #2 来解决问题中的示例。

您是否采用这种方法取决于您的应用程序的优先级。这种类型的结构是以额外的开发和查找开销为代价的。另外,如果每个单独的代码都有自己的业务规则,那么为每个所需代码创建一个新列是不切实际的。

但是,如果您不想担心将应用程序与代码表的内容同步,这可能是值得的。

于 2021-11-18T15:37:13.117 回答