0

这一直是开发人员之间的鸡与蛋问题。您在哪里存储应用程序规则中使用的业务值。(在 ASP.NET、窗口窗体或任何数据驱动的应用程序中)

我见过人们创建表来存储文本和值表示,然后将这些记录链接到代码中(通过 ID 或文本名称)。对我来说,这是最糟糕的方式:

  • 您必须维护表并为每个表创建管理模块
  • 您每次需要访问业务价值时都已阅读该表
  • 如果没有预先填充数据库,您的应用程序将无法工作 -

大多数开发人员告诉我这是我不购买的“最佳实践”,因为与我将业务价值直接放在应用程序这样的方法相比,它并没有带来任何好处:

       公共枚举 SourceLocation
        {
            数据库 = 0,
            文件 = 1,
            用户输入 = 3        
        }

然后在来自/到数据库的 [Column] 上使用整数,该数据库直接转换为数据对象上的 Enum,因此逻辑可以直接说:

    if(DataObject.Column == SourceLocation.File)
       //从文件中读取

这解决了上述所有问题,但是当您在应用程序之外的数据库上运行报告时,您需要在 SQL 中转换这些值。

所以我仍然想知道是否还有开发人员使用的另一种“更好”的解决方案或模式。我的意思是每个数据驱动的应用程序都必须有一个解决这个问题的方法/设计,这个问题从一开始就存在。

4

1 回答 1

2

我不太确定我是否同意您的观点,将这些值存储在枚举中比将它们存储在某种外部数据源中为您提供的所有好处。

您必须维护表并为每个表创建管理模块

诚然,将值存储在外部数据源中确实会增加一些架构开销。但是,如果您使用任何类型的 ORM 来处理您的数据访问和代码生成,这将是一项非常小的工作。

我不确定您所说的“管理模块”是什么意思,但我假设您指的是存储库,而不是用户自己管理选项的界面。如果替代方法是将值放入枚举中,我不明白为什么需要后者,因为用户也无法自己管理这些值。

就“维护”表而言,您实际上不需要做更多的维护,而不是通过在枚举中添加或删除值。正如 JonH 指出的那样,枚举路由要求您重建和重新部署整个应用程序,而不是简单地从数据源中添加或删除行。对我来说,这是一个更大的维护负担。

您每次需要访问业务价值时都已阅读该表

不正确,因为我假设这些值是相当静态的,所以在应用程序启动时缓存这些值并完成它是非常简单的。

如果没有预填充数据库,您的应用程序将无法运行

所以呢?如果应用程序是数据驱动的,那么将要求部署和配置数据库是部署计划的一部分。在脚本中添加 2 或 3INSERT条语句会增加部署过程的复杂性吗?

这解决了上述所有问题,但是当您在应用程序之外的数据库上运行报告时,您需要在 SQL 中转换这些值。

最重要的是,这是在外部存储这些值的最令人信服的原因。鉴于这些值在报告中使用的事实意味着它们在您的应用程序范围之外具有意义。这意味着当其他地方需要它们时,您必须每次都复制这些知识。系统中的任何重复都会增加额外的维护负担,并增加在未来更新中引入错误的机会。

最后,枚举在数据绑定到 UI 元素方面往往更加困难。如果可以,他们不允许向用户显示“漂亮”的值名称。相反,它们显示为包含“UserStoredFile”和“PickAndChooseAnotherEnumValue”等项目的下拉框。除了将枚举值关联到单独的字符串(更多重复,请参见上一段)之外,没有办法克服枚举的这种限制。

虽然看起来没什么大不了的,但任何体面的开发人员都应该关心这样的小细节。关注整个用户体验很重要。很有可能,如果您不是特别注重细节,那么您的系统中除了 UI 之外可能还有很多其他地方也会出现问题。不可否认,最后一点更像是一种主观的肥皂盒类型的论点:)。

我同意您的观点,仅存储这些值并不能证明向您的应用程序添加数据库是合理的。但是,您会注意到我通常会说external datasource。您没有理由不能将您的应用程序设置为从 XML 或某些其他类型的外部配置文件中提取这些值。但是,如果您已经拥有数据库,则不妨将其全部保存在一个地方。

编辑:

使用这些对象非常简单,它们只是集合。它们比枚举更自然地进行数据绑定,我想在数据驱动的应用程序中这很重要:

// Bind a collection of SourceLocation to an ASP.net dropdown list
ddlSourceLocations.Datasource = GetSourceLocations();
ddlSourceLocations.DataTextField = "LocationName";
ddlSourceLocations.DataValueField = "LocationId";
ddlSourceLocations.DataBind();

当然,就像你提到的,这对于枚举来说当然不是不可能的,它通常不是那么好。

将这些“业务价值”通过枚举变成完整的对象还可以让您在未来拥有更大的灵活性,如果SourceLocation需要超越名称和 ID 的概念。

让我们想象一下,稍后将“IsRemote”属性添加到 SourceLocation,以表示该位置位于单独的机器上。 SourceLocation现在能够适应需要此属性的规则:

if(myDataObject.SourceLocation.IsRemote) {
    // If the location is remote, do something extra   
}

您还可以SourceLocation通过此属性过滤集合,以防您有一些代码需要所有IsRemote为真的位置:

var remoteLocations = GetSourceLocations().Where(x => x.IsRemote);

然而,枚举在某一方面确实比数据驱动对象具有明显的优势,那就是当它们被用作应用程序常量时。事实上,这就是一个枚举,一组常量。当静态值被实现为动态的、数据驱动的规则时,更难以有效地编写针对静态值的规则。

在您的具体示例中,这是正确的。您的所有规则实际上是“如果源位置 == 1,则执行此操作”。我永远不会想要一堆魔法整数漂浮在我的应用程序周围,所以我肯定会定义一个像上面那样的枚举。

这是否意味着在这种情况下我将只使用枚举并放弃将值持久保存在外部数据源中?不一定,这完全取决于特定值在系统上下文中的使用方式。在您的示例中,这些值似乎在整个域中具有重要意义,而不仅仅是单个应用程序。您将它们描述为“业务价值”,并提到它们用于其他应用程序,例如报告。对我来说,提供一个可以共享这些知识的中心位置是完全合适的,除了在枚举中定义它们之外,我还会保留它们。

你可能会说,“等等……这不是重复吗?这不是很糟糕吗?” 好吧,是的,但不亚于使用仅枚举路线,您仍然可以获得将业务价值设计为成熟领域对象的设计奖励。

于 2012-09-13T18:13:54.200 回答