2

想象一个具有两个实体/对象的 Web 服务,Room 和 Person,其中 Room 通过 Room.Occupants 属性集合公开其中的人员。每个实体都有一个 LastModified 日期。

如果一个房间的新表示被 PUT 到服务中,并且一个居住者被移除,这是否应该改变房间上的 LastModified?

答案对缓存有影响。

您可以认为实际修改的实体是 Person,因为它的 RoomId 设置为 NULL。

但是对 http../rooms 的修改日期的有条件请求将无法反映房间的完整表示的变化,包括它的居住者。

如果您认为 Room应该更改其 LastModified,那么您需要更新可能有两个 Room 的时间戳,只要将 Person 写入服务并且其 RoomId 已更改。

如果 Person 拥有 PersonalBelongings 集合怎么办?这可能很快就会失控,所以对象的表示是否应该排除表示任何关联的集合以避免所有这些复杂性?

卢克

4

4 回答 4

3

由您决定在您的领域中什么是有意义的。

当有人离开房间时,这会“修改”房间吗?我不认为有一个正确的答案,尽管从隐喻中得出的直觉是不,当有人进入或离开时房间没有被修改。 这是对房间在现实世界中的行为方式的常识性理解,尽管我知道您仅将房间和人用作示例类型,并且您的实际场景中的问题可能并不那么明确。

关键是要保持一致。

第一步是说“存在的房间不允许 PUT”。您可以通过 PUT 使“添加房间”成为不可能,这将消除您的初始场景的可能性,即 PUT 一个房间里少一个人。要将一个人从一个房间“移动”到另一个房间,您可以向具有给定 ID 的人发布信息。

另一方面,您可能希望向房间发布消息以更新房间中的居住者列表。在这种情况下,您可能不希望允许反向 POST 移动一个人。

您选择哪个选项取决于您 - 只要它是一致且合理的,就可以了。


另一个合理的步骤是适当地命名“LastModified”。在您的 Room 和 Person 场景中,更合适的名称可能是“LastContentsChange”或“LastOccupantsChange”。

接下来的合理问题是,我的应用程序是否需要知道房间的住户组上次更改的时间?当然,这是一个只有你才能回答的问题。

所以你迭代——你做出一些临时的设计决定,然后考虑当你在行动中使用该设计时的含义。然后你重新审视和改变一些设计决策,并进行一些新的测试。等等。

能够使用简化的后备存储快速对您的设计进行原型设计,只是为了尝试想法,这可能会有所帮助。

于 2012-07-03T15:48:54.210 回答
3

当您继续使用实体和对象等术语定义基于 REST 的系统时,您将遇到这样的问题。REST 处理资源和表示,虽然这看起来像是微不足道的文字游戏,但在处理此类问题时会产生巨大的差异。

HTTP 关心的 LastModified 日期是表示的最后修改日期。如果我们关心的资源是/room/45/occupants它的表示显示房间里的人和刚刚离开房间的人,那么我会说毫无疑问,表示应该有一个新的 LastModfied 值。

隐藏在 REST 接口后面的房间和人员实体发生的事情的细节是一个完全独立的问题。

资源和表示的设计与域实体的设计不同,就像域实体与用于存储这些实体的数据库结构不同一样。

于 2012-07-03T16:19:50.230 回答
1

你以经典的鸡和蛋问题结束。你必须决定 Persons 是否在房间“外面”有生命。如果是这种情况,那么您可以找到具有 NULL RoomId 的 Persons,并且Persons 将住房间外,因此 Room.occupants 将保存对 Persons 的引用(URL)(而不是包含人员)。

如果 Persons 只存在于房间内,那么您不能拥有 RoomID 为 NULL 的 Persons,因为对 Persons 的所有集合管理都是在 Rooms 内进行的(添加新的 Person,删除一个),并且可以有效地修改/更新 LastModified、入住人数等。

然后,您必须决定由谁管理交易。在第二种情况下(人不住在房间外),房间本身存储所有状态,因此更新状态不需要事务(您只需删除或添加一个人,房间的状态就会改变)。

在第一种情况下,请注意房间和人员是相互关联的。如果事务由客户端管理,则客户端必须确保在删除人员时始终执行必要的步骤。那是:

  1. 删除人员
  2. 使用 PUT 更新房间(修改 occupants 中的引用以反映 Person 删除)

如果在服务器中进行状态管理,删除 Person 会使 Room 被修改。这会在删除 Person 时强制使 Room 副本无效,并且由服务器将对 Person 的更改级联到 Room(即更新其 LastChanged)。这是服务器中的硬编码逻辑。

于 2012-07-03T15:52:00.810 回答
1

一般来说,我认为一个资源的更改将意味着先前获取的包含该资源的集合现在无效。我希望获取该集合的新HEAD请求GET将具有更新的Last-ModifiedETag头。

我认为@Darrel Miller 在资源和域实体之间的区别上是正确的。对我来说,这也意味着它们的生命周期不同,应该单独跟踪。在我看来,一个资源的变化会触发相关集合资源的变化。

话虽如此,您将如何在不失控的情况下实施它?我已经看到存储在数据库中的资源状态(与实体分开)。它可以像将 URL 映射到日期戳一样简单,但这实际上取决于您的资源布局。

至于更新,我已经看到使用数据库触发器来更新资源状态。虽然它是直截了当的。我发现它不是可扩展的,只是简单的混乱。我最喜欢的策略是在服务实现内部创建应用程序事件。这允许我在资源更改时异步发布事件。事件处理程序相应地更新其他资源状态。我看到了许多实现应用程序事件的方法。它类似于记录或记录历史,所以我认为应用程序事件是一个横切关注点。所以,我喜欢使用AOP,但你应该使用任何可行的方法。

于 2012-08-24T17:05:28.137 回答