代码之家  ›  专栏  ›  技术社区  ›  Jamie Ide

允许空值与默认值

  •  1
  • Jamie Ide  · 技术社区  · 15 年前

    我正在开发一个ASP.NET项目,它取代了许多现有的纸质表单。其中一个要求是,用户可以在任何状态下保存表单,也就是说,他们可以创建一个新的空白表单,并立即在没有数据或部分数据的情况下保存它。每次保存时我都在验证数据类型,但在用户将表单标记为已完成之前,不会验证必需字段。

    我不确定在数据库和域模型中处理这个需求的最佳方法是什么。据我所见,我有两个选择:

    1. 对于可能没有数据的任何字段,允许为空。这看起来像是“正确的”方法,但它要求几乎每个数据库字段都允许空值,并且我必须围绕许多可以空值的类型进行编码。此外,当表单完成时,数据库中不会强制执行任何必需的字段。
    2. 用有意义的默认值填充我的业务对象。在某些情况下,对于我可以使用的许多(但不是全部)字段,都有意义的默认值。这种方法近乎于“神奇数字”,这让我很不舒服。

    哪种方法最好?还是有第三条路?我不愿意走极端,比如分桌。

    编辑后补充:自从我接受回复后,我想在这方面做些扩展。我对拆分表不感兴趣的主要原因是,提交项目后,表单上的数据将用于为另一个系统(即记录系统)生成数据。此时,原始表单数据不太可能被修改或用于报告。

    10 回复  |  直到 15 年前
        1
  •  1
  •   Marc Gravell    15 年前

    如果没有一个合理的默认值,并且您不想分割数据,那么nulls几乎肯定是您的最佳选择。数据库在完成时不会验证它们是否为空…好吧,如果你不想分割桌子,你就没什么办法了(除了使用 CHECK 约束,或 INSTEAD OF 触发器以运行验证)。但数据库不是 只有 负责数据验证的地方。你的应用程序逻辑也能做到。

        2
  •  2
  •   Tom Ritter    15 年前

    我不明白你为什么不想把桌子分开。我不知道你在哪个领域,但在任何一个领域,我都可以想象有两类人:

    • 已提交表单的人
    • 没有的人

    作为一名业务主管,我不在乎第二个。但首先我非常关心,他们需要正确地输入所有的数据。

    它还提高了效率——关于聚合数据的大多数查询将在第一个表上进行,而不是在第二个表上进行。第二个表将仅用于索引查找。

        3
  •  2
  •   Jason Musgrove    15 年前

    如果拆分表(是否有多个表?)不是一个选项,我将考虑创建单个表来存储不完整表单的对象的序列化,并且只在用户完全提交表单时将表单提交到“real”表。

        4
  •  1
  •   Razvan Stefanescu    15 年前

    您可以在每列上使用一个带有“allow nulls”的临时表来存储包含部分或不包含数据的表单,并在用户将表单标记为已完成时将数据复制/移动到最终表。这样,您就不需要依赖默认值(用户可能会忘记更改),您可以在任何状态下保存,最终仍然可以进行验证。

        5
  •  1
  •   RolandTumble    15 年前

    这是一种需要拆分表格的情况。我知道你说过你不想这样做,甚至在一条评论中说,“这个项目不需要这么努力”。但这确实是最好的解决方案。

    设置初步表,其中包含除键可以为空之外的所有内容。当用户将表单标记为完成并通过验证时,将其移动到最终表。这不仅是正确的做法,而且在处理完成的表单时,它可能比“围绕可空值进行编码”的工作要少。

    如果需要查看所有已完成或未完成的表单,请创建联合视图。

        6
  •  0
  •   JB King    15 年前

    我会选择第一个选项,但会向数据库表中添加一列,这样当表单完成时,它就会被标记。然后,对于使用表单数据的任何内容,只需检查表单是否已完成。

    这是我的建议。

        7
  •  0
  •   Quassnoi    15 年前

    NULL 索引无法搜索值。

    如果需要发出类似“选择前10个没有填写特定字段的表单”的查询,则此查询将使用 FULL TABLE SCAN 可能效率不高。

    Oracle 不区分 无效的 和空字符串,但其他数据库可以。您可能希望将空字符串设为 DEFAULT 用于未填充的字段,并在搜索中使用它。

    如果你不需要搜索未填充的字段,那么就让它们 无效的 .

        8
  •  0
  •   Joe Phillips    15 年前

    空通常意味着“不知道”(在数据库中),而空字符串实际上可以表示空字符串。

    在您的案例中,我倾向于使用null作为“不知道”值。当您打印出数据时,您只需假设任何空值都意味着一个空字符串。

        9
  •  0
  •   KM.    15 年前

    检查约束+视图

    如果没有状态字段,请添加一个,这样您就可以知道它已完成。

    • 在该状态字段上添加检查约束,以便在任何列为空时都不能将其标记为已完成。

    在“已完成”表单上编写查询时,如果执行以下两个选项之一,则可以忽略检查所有位置的空值:

    • 只需在WHERE子句中添加status=“f”完成
    • 只查看成品

    使用“完成视图”时,您不必执行所有验证检查,也不必担心结果中显示的未完成视图。

        10
  •  0
  •   Jesse Taber    15 年前

    我也遇到过类似的情况,虽然我还没有找到解决方案,但我一直在玩弄使用简单的XML序列化来存储临时文档数据的想法。如果生成对对象中的数据建模的简单类(可能在需要时使用可以为空的类型),那么很容易将屏幕中的数据填充到这些对象中,将它们序列化为XML,然后将它们存储在临时的“临时”表中。当您的用户完成工作并希望提交或完成文档时,您将对序列化数据执行所有所需的验证,最终使用适当的数据结构和约束将其放入“real”表中。