如何处理(country-)代码列表中的弃用值

时间:2012-08-21 13:45:09

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

假设我们拥有所有国家/地区的代码列表,包括其国家/地区代码。国家/地区代码是Countries表的主键,它在数据库的许多位置用作外键。在我的申请中,这些国家通常显示为多种形式的下拉列表。

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

我有两个目标:

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

我看到两个选项:

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

还有其他想法吗?

4 个答案:

答案 0 :(得分:6)

我经常处理这个场景,并使用'Active'标志来解决问题,就像你描述的那样。当我使用值填充下拉列表时,我只加载“活动”数据并包含最多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";
        }
    }

答案 1 :(得分:1)

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

这就是我要做的事情:

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

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

答案 2 :(得分:0)

您可以使用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);
    }
}

答案 3 :(得分:0)

为什么你仍然想用他们的旧国家代码显示(例如)客户地址?
如果我理解正确的话,你现在仍然有'地址'记录仍然指向'塞尔维亚和黑山'。我想如果你解决了这个问题,你现在的问题将不复存在。

“国家”一词可能有点误导:并非ISO 3166中的所有“国家”实际上都是独立的。相反,其中许多是地理上独立的领域,是其他国家的法律部分或依赖。

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

那么为什么不让'withdrawn'字段/表指向新的country-id。如果此字段为空,您仍然可以检查(例如,在sql中,因为您已经在使用表),如果需要,则可以进行真/假检查。

我看待它的方式:“国家/地区”代码可能会发生变化,国家/地区可能会合并,而国家/地区可能会分开。

如果国家/地区更改或合并,您可以使用简单查询更新地址记录。

如果国家存在分歧,您需要一种方法来确定哪个地址属于哪个国家/地区。 你可以使用一些自动化系统来做这件事(并写一些关于它的书籍。) OR
(当它是一个像网站这样的论坛时),你可以要求仍然有一个退出国家的用户在他们的帐户中指向多个替代品,以便在登录时更新他们的国家/地区,他们只能从新国家/地区的列表中选择在撤销字段中指定。

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

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

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

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

在您的方案中实现这个想法(没有停机时间):

  • sql语句,用于构建一个以数字ID为主键的新国家/地区表。
  • 使用新字段“country-id”更新地址记录的sql语句,并使用与该记录的地址字段中指定的国家/地区代码对应的新国家/地区表中的country-id填充此字段。
  • (sql语句to)创建撤销表并在其中填充正确的数据。
  • 然后重写为表单提供数据的sql语句
  • 添加支票并“询问用户更新国家/地区”例程
  • 让新表格上线
  • 等待/看到意想不到的错误
  • 从“address”-table
  • 中删除旧的country-table和(now unused)country-code列

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