【问题标题】:How to deal with deprecated values in (country-)code lists如何处理(国家/地区)代码列表中已弃用的值
【发布时间】:2012-08-16 21:08:28
【问题描述】:

假设我们有一个包含所有国家/地区代码的代码列表。国家代码是国家表的主键,它在数据库的许多地方用作外键。在我的应用程序中,国家通常在多个表单上显示为下拉菜单。

过去存在的一些国家现在已经不存在了,例如Serbia and Montenegro,其国家代码为SCG。

我有两个目标:

  • 不允许用户使用这些旧值(因此在插入数据时这些值不应在下拉列表中可见)
  • 用户应该仍然能够(只读)打开旧的东西,在这种情况下,不推荐使用的值应该在下拉列表中可见。

我看到两个选项:

  • 重命名不推荐使用的值,例如从“CountryName”改为“!!!!!CountryName”。这种方法最容易实施,但缺点也很明显。
  • 将 IsActive 列添加到 Country 表,并将所有不推荐使用的值设置为 false,将所有其他值设置为 true。在用户可以插入数据的所有表单上,仅显示活动值。在只读表单上,我们可以显示所有值(包括已弃用的值),以便用户能够显示旧数据。但是在我的一些表单上,用户应该也可以编辑数据,这意味着不推荐使用的值应该对他隐藏。这意味着,每个 Dropbox 都应该有一些这样的初始化逻辑:如果显示的数据是只读的,则在 Dropbox 中包含不推荐使用的值,如果数据也用于编辑,则排除它们。但这也需要大量的工作并且容易出错。

还有其他想法?

【问题讨论】:

  • 这是一个时态数据库。添加 valid_from 和 valid_to 字段。如果 valid_to 为 null,则它处于活动状态。

标签: c# .net vb.net database-design


【解决方案1】:

我经常处理这种情况,并使用“活动”标志来解决问题,就像你描述的那样。当我用值填充下拉列表时,我只加载“活动”数据并包含最多 1 个不推荐使用的值,但前提是它正在被使用。 (即,如果我正在查看人员记录,并且该人员的国家/地区已弃用,则该国家/地区将与活动国家/地区一起包含在下拉列表中。我在只读和编辑模式下执行此操作,因为在我的案例,如果一个人记录(例如)列出了一个已弃用的国家,他们可以继续使用它,但是一旦他们将其更改为非弃用的国家,然后保存它,他们就永远无法切换回来(你的用例可能会有所不同)。

因此,关键区别在于,即使在只读模式下,我也不会将所有已弃用的国家/地区添加到 DDL,而只是将已弃用的国家/地区添加到我正在查看的记录中,即使这样,也只有在该记录已被使用。

这是我在加载下拉列表时使用的逻辑示例:

    protected void LoadSourceDropdownList(bool AddingNewRecord, int ExistingCode)
    {
        using (Entities db = new Entities())
        {
            if (AddingNewRecord) // when we are adding a new record, only show 'active' items in the drop-downlist.
                ddlSource.DataSource = (from q in db.zLeadSources where (q.Active == true) select q);

            else // for existing records, show all active items AND the current value.
                ddlSource.DataSource = (from q in db.zLeadSources where ((q.Active == true) || (q.Code == ExistingCode)) select q);

            ddlSource.DataValueField = "Code";
            ddlSource.DataTextField = "Description";
            ddlSource.DataBind();

            ddlSource.Items.Insert(0, "--Select--");
            ddlSource.Items[0].Value = "0";
        }
    }

【讨论】:

  • 很好的解决方案,谢谢。我可能会将此方法设为静态并添加下拉菜单作为另一个参数,但其余的正是我所需要的。
【解决方案2】:

如果您将记录显示为只读,为什么还要加载常规数据?

我会这样做:

在任何情况下,记录都将包含国家代码,我还建议返回国家描述(诚然这会降低效率),但是当用户加载“旧东西”时,业务服务会识别此记录将是只读,而且您不必费心加载国家/地区列表(这会使事情变得更有效率)。

在我的演示服务中,我通常会检查国家列表是否为空。如果不是 (r/w) 将数据加载到列表框中,如果是 (r/o) 从记录中的数据填充列表框 - 列表中的单个条目等于只读。

【讨论】:

    【解决方案3】:

    您可以使用 CollectionViewSource 进行过滤,也可以创建一个使用 LINQ 过滤完整列表的 Public Enumerable。

    CollectionViewSource Class

    LINQ FieldDef.DispSearch 是活动条件。 IEnumerable 的性能比 List 好一点。

    public IEnumerable<FieldDefApplied> FieldDefsAppliedSearch
    {
        get
        {
            return fieldDefsApplied.Where(df => df.FieldDef.DispSearch).OrderBy(df => df.FieldDef.DispName);
        }
    }
    

    【讨论】:

      【解决方案4】:

      为什么还要显示(例如)客户地址及其旧国家/地区代码?
      如果我理解正确,您目前仍然有指向“塞尔维亚和黑山”的“地址”记录。我想如果你解决了这个问题,你现在的问题就不存在了。

      “国家/地区”一词可能有点误导:并非 ISO 3166 中的所有“国家/地区”实际上都是独立的。相反,它们中的许多是地理上独立的领土,在法律上是其他国家的一部分或附属国。

      另请注意,“撤回的国家/地区代码”保留 5 年,意味着 5 年后它们可以重复使用。因此,不再使用国家/地区代码本身作为主键对我来说是有意义的,尤其是如果由于历史原因您需要回溯以前的国家/地区代码。

      那么,为什么不创建指向新国家/地区 ID 的“已撤销”字段/表。您仍然可以检查(例如在 sql 中,因为您已经在使用表)该字段是否为空,以便在需要时进行真/假检查。

      我的看法:“国家/地区”代码可能会改变,国家/地区可能会合并,国家/地区可能会分裂。

      如果国家/地区发生变化或合并,您可以通过简单的查询来更新您的地址记录。

      如果国家有分歧,您需要一种方法来确定哪个地址属于哪个国家。 您可以使用一些自动化系统来执行此操作(并为此撰写冗长的书籍)。

      (当它是一个类似网站的论坛时),您可以要求仍然有一个退出国家/地区的用户指向他们帐户中的多个替代项,以便在登录时更新他们的国家/地区条目,他们只能从新国家/地区列表中选择在撤回的字段中指定。

      想想这个简化的国家/地区表设置:

      id  cc  cn                     withdrawn
      1   DE  Germany
      2   CS  Serbia and Montenegro  6,7
      3   RH  Southern Rhodesia      5
      4   NL  The Netherlands        
      5   ZW  Zimbabwe
      6   RS  Serbia
      7   ME  Montenegro
      

      在此示例中,国家 ID 为 3 的地址记录通过对国家 ID 5 的查询进行更新,无需用户交互(或其他解决方案)。
      但是,指定 country-id 2 的地址记录将被要求选择 country-id 6 或 7(当然在呈现给用户的文本中,您使用国家名称)或选择执行您的自定义自动更新例程。

      另请注意:“撤回”是一个重复组,因此您可以/应该将其放入单独的表格中。

      在您的场景中实施此想法(无需停机):

      • sql 语句以数字 id 作为主键构建新的国家/地区表。
      • 使用新字段“国家/地区 ID”更新地址记录的 sql 语句,并使用与该记录的地址字段中指定的国家/地区代码对应的新国家/地区表中的国家/地区 ID 填充此字段。
      • (sql 语句)创建撤销的表并在其中填充正确的数据。
      • 然后重写为表单提供数据的 sql 语句
      • 添加检查并“要求用户更新国家/地区”例程
      • 让新表单上线
      • 等待/查看意外错误
      • 从“地址”表中删除旧的国家/地区表和(现在未使用的)国家/地区代码列

      我很好奇其他专家对这个想法的看法!

      【讨论】:

      • 在我的例子中,塞尔维亚和黑山应该指向哪里——塞尔维亚还是黑山? :P
      • 我明白你的意思。但是,您已经拥有的数据呢?那已经遭受同样的问题了吗?假设您有 10 条记录指向“塞尔维亚和黑山”。您如何将它们拆分为“塞尔维亚”或“黑山”?按邮政编码?
      • 为我的想法添加了详细解释
      • 添加实施建议
      • 我的业务逻辑不允许我接触旧数据,所以在我的示例中这不是一个选项。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-18
      • 2022-01-16
      相关资源
      最近更新 更多