【问题标题】:Which one is a generally better concept: store selected item or only its key (aka id)?哪一个是一个更好的概念:存储选定的项目还是只存储它的键(又名 id)?
【发布时间】:2014-09-07 01:15:21
【问题描述】:

我现在对一般的视图模型设计概念有一个很大的困境。我的意思是一般的,就像它不完全绑定到给定的语言或环境一样:当我为 Winforms、WPF 或 KnockoutJS 编写视图模型时,我遇到了同样的困境。

作为一个简化的用例,假设我有一个视图,我必须从两个选择框中选择一个国家和一个城市。两者都在数据库中以唯一 ID、名称和其他一些相关信息(例如 - 比如说 - 人口)表示。现在想象一下,我必须在例如视图的标题中呈现当前所选数据的文本形式,例如“您已选择英国伦敦”。现在这是我创建视图模型的两个替代方案,我将尝试列举我已经在每个版本下面考虑的优点/反面。代码以伪方式编写,尽可能通用。

class RegionModel {
  ID: number;
  Name: string;
  Population: number;
}

版本 1:存储所选对象。

class MainView {
  SelectedCountry: RegionModel;
  SelectedCity: RegionModel;

  SelectionInfo: string; // computed, should return the "You've selected ...." caption

  Countries: List<RegionModel>; // datasource for country select
  Cities: List<RegionModel> // datasource for city select
}

优点:

  • 由于所选内容简单明了且易于理解 项目的类型与可选项目的类型相同。
  • 很容易计算诸如“您已选择...”之类的信息,因为所有 当前选定项目的成员直接存在。

缺点:

  • 它拥有比消费者 API 通常需要的更多信息。通常 它只需要 ID。
  • 如果在客户端应用程序中使用,则整个选定对象将是 返回到服务器,占用带宽。
  • 如果消费者 API 只需要 ID(在大多数情况下),我必须 在我通过之前解决某种转换。在网络应用程序中可能 例如,在序列化为 JSON 期间。

版本 2:仅存储所选项目的 ID

class MainView {
  SelectedCountryID: number;
  SelectedCityID: number;

  SelectionInfo: string; // computed, should return the "You've selected ...." caption

  Countries: List<RegionModel>; // datasource for country select
  Cities: List<RegionModel> // datasource for city select
}

优点:

  • 它的高效之处在于它只包含以下信息 很可能是消费者 API 需要的。
  • 无需额外转换,高效能通过 几乎“原样”到服务器端或其他 API。

缺点:

  • 不是那么简单易读(在我看来)。
  • 计算信息字符串怎么样?现在更难了,我需要 从选择源列表中获取所需的成员 通过给定的 ID 进行搜索,因此它在很大程度上取决于 那些列表(我的意思是该项目必须存在于那里)。

我希望它不会因为没有建设性而很快关闭。任何形式的建议、想法或经验将不胜感激。另外,如果答案是“视情况而定”,请尝试在何时何地使用哪个。

更新

我认为我的问题有点不清楚。我知道从数据库实体中解耦视图模型,这里我从来没有提到数据库实体。我提到了一个“抽象消费者 API”。在一个具体的场景中:如果 API 需要所选项目的名称,而我的 API 只需要 ID,我应该选择哪个替代方案,应该在哪里进行转换?

例如,我的服务器需要这样的数据格式 (JSON):

{
  "SelectedCountryID": 2,
  "SelectedCityID": 5
}

没有别的。我怎么能优雅地处理它?我想通过手动转换来避免重复自己。

【问题讨论】:

    标签: c# wpf mvvm knockout.js viewmodel


    【解决方案1】:

    基于 MVVM 模式,您的 viewModel 应该是一个具有您需要在视图中显示的所有属性的对象。 ViewModel 应该只用于严格绑定到视图。无论如何,你的例子在我看来不是很好。在存储某些东西的情况下,您不应该考虑 viewModel,请多考虑呈现数据。

    请记住,在数据库中有数据之前,您必须将其插入。因此,如果您有一些带有名字和姓氏的表格,用户首先必须填写此表格,并且必须将数据插入数据库,没有它您没有任何 ID。

    总结一下,我认为 viewModel 应该具有您必须向最终用户展示的属性。

    【讨论】:

    • 是的,我明白了,“存储”对我来说是一个不幸的词用法。这里的演示不受两个版本中的每一个的影响。通常绑定到一个选择框让您有机会将所选项目绑定为对象(版本 1),或仅使用其 id(版本 2),用户将看到相同的内容。
    • 但是您的示例侧重于下拉列表,您确实拥有键和值,但是其他表单元素(如文本框、单选按钮等)呢?但是如果您有 viewModel例如:FirstName、LastName、City(绑定到下拉列表),而您只想知道 City 应该是一个复杂对象(具有键和值属性)还是普通属性(仅 int 表示键或字符串表示值),我的答案是看情况。如果您需要在服务器端使用值进行操作,最好有复杂的对象,如果不是,可以只使用 ID 来处理这个对象。
    • 是的,我的意思是这样。使用文本框或其他简单的输入,问题就简单多了。如果消费者 AOI 只需要键,但我的视图也需要所选项目的文本,我应该如何处理?我已经更新了我的问题以澄清这一点。
    • 好的,现在很清楚了。如果这是一个简短的 constance 集合,我更喜欢使用由 Id 和 Description 或枚举组成的复杂对象。我更喜欢这样,因为我有更多选项可以在服务器端操作该对象,而不仅仅是保存或更新。各种框架、语言支持以不同方式绑定到下拉列表(选择标签)。更重要的是,如果您需要在视图中动态生成下拉列表,您不能仅基于 id 执行此操作,但如果您有复杂对象(id、值)的集合,这不是问题。
    • 您可以做的是收集复杂对象以显示下拉菜单和其他属性,例如“selectedItemKey”。
    【解决方案2】:

    根据您的 数据源 的实施方式,可能没有区别:如果您正在检索国家和城市列表,您可以存储对所选值的引用,存储到其中一个字段或其在列表中的索引。

    尽管如此,您应该将视图模型实体与数据库实体分离,并仅将视图所需的那些字段放入视图模型中。这样,您的信息流量最小化,您的代码受数据库更改的影响较小。

    编辑跟随 OP 的更新:

    谈到与 API 而不是数据库交互,我认为您可以应用相同的想法,只需将“数据库实体”替换为“服务层实体”(例如,传入/传出服务器的 JSON)。将返回的数据放入您的视图模型对象中,并保存您需要的那些属性。显然,您可能还需要存储id,如您所说,稍后您需要引用相同的实体。

    从理论上讲,您不应包含视图未使用的任何其他字段,但您可以根据您的要求这样做。例如,如果您需要将这些字段传回服务层,并且您不想通过id 再次查询以检索服务实体。但是,还有其他替代方案(例如,某种缓存),确切的平衡取决于您的要求。

    【讨论】:

    • 感谢您的补充。我想我想太多了。我有一种感觉,我试图破坏我不应该做的事情。我看到我想使用与视图模型和服务 DTO 相同的表示,这在这种情况下似乎不起作用。你是对的,在这种情况下,API 模型就像一个数据库实体。我想我会接受你的回答,因为这让我认为我很可能使用了糟糕的设计。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-16
    • 2012-07-17
    • 2012-03-10
    • 2010-09-12
    • 2011-04-25
    • 2010-09-20
    相关资源
    最近更新 更多