【问题标题】:Flex-Cairngorm/Hibernate - Is EAGER fetching strategy pointless?Flex-Cairngorm/Hibernate - EAGER 获取策略是否毫无意义?
【发布时间】:2011-09-02 20:28:14
【问题描述】:

我会尽量简洁。我正在为我的应用程序使用 Flex/Hibernate 技术。我还为 Flex 使用 Cairngorm 微架构。因为我是初学者,所以我可能误解了 Caringorm 的 ModelLocator 目的。我有以下问题...

假设我们有下一个数据模型:

USER  ---------------->  TOPIC  ------------->  COMMENT     
      1              M          1           M 

用户可以启动许多主题,主题可以有许多 cmets 等。这是一个非常简单的模型,仅举个例子。在 hibernate 中,我使用 EAGER 获取策略 来处理单向 USER->TOPIC 和 TOPIC->COMMENT 关系(这里没有关于最佳实践等的问题,这只是问题的示例)。

我的 ModelLocator 如下所示:

...
public class ModelLocator  ....
{
    //private instance, private constructor, getInstance() etc...
    ...

    //app state
    public var users:ArrayCollection;
    public var selectedUser:UserVO;
    public var selectedTopic:TopicVO;
}

因为我使用急切获取,所以我可以“遍历”我的 Flex 客户端上的所有对象图,而无需访问数据库。只要我不需要插入、更新或删除某些域实例,就可以了。但是当这种情况发生时,同步问题就出现了。

例如,如果我想从某个 UserListView 中显示有关某个用户的详细信息,当用户(演员)在列表中选择该用户时,我将在 UserList 中获取所选索引,从用户 ArrayCollection 中获取元素在选定索引处的 ModelLocator 中并显示有关选定用户的详细信息。

当我想插入新用户,好的时,我将把该用户保存在数据库中,并在 IResponder 结果方法中将该用户添加到 ModelLocator.users ArrayCollection 中。

但是,当我想为某些用户添加新主题时,如果我仍然想使用 EAGER 获取的便利,我需要重新加载用户列表。 . 并向选定用户添加主题...如果用户在其他位置(间接),我还需要在那里插入主题。 更新更糟糕。在那种情况下,我什至需要写一些逻辑......

我的问题:这是在 Cairngorm 中使用 ModelLocator 的好方法吗?在我看来,由于提到,EAGER fetching 在某种程度上是毫无意义的。在使用 EAGER fetching 的情况下,Flex 客户端上的同步可能会成为大问题。我应该总是点击数据库来操作我的域模型吗?

编辑: 看来我自己说得不够清楚。对不起。

好的,我在技术堆栈中也使用 Spring 和带有 flex/spring (de)serializer 的 DTO(DVO) 模式,但我只是想远离它,因为我试图指出你如何保持同步flex 应用程序中的数据库状态。我什至没有提到多用户场景和轮询/推送主题,这也许是我的解决方案,因为我使用标准的请求-响应机制。我没有提供一些具体的代码,因为这对我来说似乎是概念问题,我使用标准 Cairngorm 术语来解释我用于类名、变量名等的伪名。

我将再次尝试“简化”:您有用于管理上述域的 flex 客户端(每个域类的 CRUD),您有 ListOfUsersView(显示具有基本信息的用户列表关于它们),UserDetailsView(显示用户详细信息和用户主题列表,每个主题带有删除选项),InsertNewUserTopicView(插入新主题的表单)等。

每个视图显示一些信息是与ModelLocator同步状态变量,例如:

ListOfUsersView ------binded to------> users:ArrayCollection in ModelLocator
UserDetailsView ------binded to------> selectedUser:UserVO in ModelLocator 
etc.

视图状态转换如下所示:

ListOfUsersView----detailsClick---->UserDetailsView---insertTopic--->InsertTopicView

所以当我单击 ListOfUsersView 中的“详细信息” 按钮时,在我的逻辑中,我在 ListOfUsers 中获取所选行的索引,然后我 获取 UserVO来自用户的对象:ModelLocator中提到的索引处的ArrayCollection,之后我将该UserVO对象设置为selectedUser:ModelLocator中的UserVO,然后我将视图状态更改为UserDetailsView(它显示用户详细信息和 selectedUser.topics)与 ModelLocator 中的 selectedUser:UserVO 同步。

现在,我单击 UserDetailsView 上的 “插入新主题” 按钮,会生成 InsertTopicView 表单。我输入一些数据,点击“保存主题”(保存成功后,再次显示UserDetailsView)出现问题

由于我急切地获取对象,我没有在提到的转换中访问数据库,因此我需要两个地方为选定用户插入新主题时关注:一个是 selectedUser 对象的实例 in users:ArrayCollection (因为我的逻辑从该集合中选择用户并在 UserDetailsView 中显示它们),和第二个是selectedUser:UserVO(为了同步成功保存操作后的UserDetailsView)。

所以,我的问题又出现了......我是否应该在每次转换时都点击数据库,我是否应该在保存后重新加载 users:ArrayCollection 和 selectedUser:UserVO 以便与 flex 客户端同步数据库状态,我是否应该在客户端保存主题一边,不打数据库,以编程方式传递我需要更新的所有地方或......?

在我看来,EAGER-ly 获取对象及其关联并不是一个好主意。我错了吗?

或者,再次“简化”:),在提到的场景中你应该怎么做?所以,你需要处理点击“保存主题”按钮,现在是什么......?

再一次,我真的试图尽可能用塑料来解释这一点,因为我对此感到困惑。所以,请原谅我的长篇文章。

【问题讨论】:

    标签: apache-flex hibernate cairngorm eager


    【解决方案1】:

    在我看来,重点不在于获取模式本身,而在于客户端/服务器交互。根据我之前的经验,我终于发现了使用纯域对象(尤其是急切获取)进行客户端/服务器交互的一些缺点:

    • 您可能必须传递所有子集合,而不必在客户端使用它们。在您的情况下,您很可能不会为您从服务器获得的所有用户显示主题和 cmets。最相似的情况是您需要显示用户列表,然后显示选定用户之一的主题,然后显示选定主题之一的 cmets。但是在当前实现中,即使不需要显示它们,您也会收到所有主题和 cmets。您很可能会在一次查询中收到所有数据库。
    • 另一个问题是获取包含所有字段(电子邮件、地址、密码、信用卡号等)的所有用户数据(或某些其他数据)可能非常不安全。

    我认为不使用纯域对象可能还有其他原因,尤其是急切获取。

    我建议您引入一些 Mapper(或 Assembler)层来将您的域对象转换为数据传输对象,即 DTO。因此,对您的服务层的每个查询都会从您的 DAO 或 Active Record 接收数据,然后使用相应的 Mapper 将其转换为相应的 DTO。因此,您可以在没有私人数据的情况下获取用户列表,并通过单独的查询来查询一些额外的用户详细信息。

    在客户端,您可以直接使用这些 DTO 或将它们转换为客户端域对象。您可以在您的 Cairngorm 响应程序中执行此操作。

    这样你可以避免很多你描述的客户端问题。

    对于 Mapper 层,您可以使用 Dozer library 或创建自己的轻量级映射器。

    希望这会有所帮助!

    编辑 关于您的详细信息,我希望获得包含必要可显示字段(如名字和姓氏)的用户列表(以显示在列表中)。说出SimpleUserRepresentationDTO 的列表。

    然后,如果用户请求编辑用户详细信息,则为该用户请求 UserDetailsDTO 并用它填写模型中的游览 selectedUser 字段。主题也是如此。

    唯一的问题是在用户详细信息编辑后显示用户列表。你可以:

    • 再次请求整个列表。优点是您可以显示其他用户执行的更改。但是如果列表太长,每次都查询所有用户可能会非常无效,即使他们是SimpleUserRepresentationDTO,数据很少。
    • 当您从服务器获取用户详细信息保存成功时,您可以在模型的用户列表中找到相应的用户并在那里替换更改的详细信息。

    【讨论】:

    • @Constantiner - 感谢您的回答。我编辑了我的问题。正如我在那里提到的,我使用 DTO(或 DVO)模式,我可以选择要从服务器端域对象映射到客户端对象的数据。如果我理解得很好,你建议我简化我的 DTO 并为我需要的每一个信息的和平点击数据库(例如,如果我需要用户主题,我会为它们查询数据库等等)?
    • 对。只需创建简单且适用的 DTO。
    • @slomir 我在回答中添加了一些细节。
    • @Constantiner - 非常感谢 (ili Hvala ;)。我明白你的意思了。我将在 DTO 中创建更好的粒度并应用您的方法。
    • @Constantiner - 抱歉打扰了,我只有一个问题。第一次,在你的回答中,你建议我一些汇编层,最准确地说是推土机。这是很棒的库,现在我明白了他的目的。现在,在服务器端,我有返回域对象的服务层。我不想改变这一点,因为将来我的应用程序可能会暴露于经典的 Spring MVC 等。创建一些适配器层来使我当前的服务接口适应 Flex 客户端调用是否合理?在适配器中,我将调用现有的服务层,按照我的意愿组装我的 DTO 并将它们返回给 flex。
    【解决方案2】:

    说实话,Cairngorm 没有什么好办法。这是一个垃圾框架。

    我不太确定您所说的急切获取的确切含义(或者您的问题到底是什么),但无论如何,它仍然是一种请求/响应类型的交易,这不应该是一个问题,除非你做的不对;在这种情况下,我看不到您的代码。

    至于框架,我建议你看看RobotLegsParsley

    【讨论】:

    • 感谢您的回答。通过 EAGER,我的意思是当我加载一些实例时,我得到了完整(或部分)的对象图(这取决于休眠关联映射和配置)。在我的示例中,我实际上获得了整个数据库,因为当我获得所有用户时,他们每个人都会获取他们的主题,每个主题的 cmets 等。为了简化,我的问题是如何将该应用程序状态(对象图)与数据库状态同步在我插入、更新、删除数据库中的域对象之后?我应该点击数据库并再次重新加载还是...?
    • 等等,您的客户是直接与数据库对话吗?除非这是一个 Air 项目,否则这是一个非常大的禁忌(只有当它是本地数据库时)。两者之间应该有某种中间层(java、php等)。无论哪种方式,都有两种获取数据的方法,即轮询或推送。轮询意味着客户端每 x 时间请求一次新数据,而推送是与服务器的持续连接,服务器自动将有关更改的信息发送给客户端,客户端对所述数据执行操作。
    • 没有。我也使用 Spring 作为中间层。但是,您提到了从服务器获取数据的两种方法:轮询或推送(我认为您描述了长轮询)。由于网络流量问题(在轮询或长轮询的情况下),我没有考虑到这一点。您是否使用(长)轮询来进行客户端/服务器同步?为投票设置多少时间?如果它太长,那么在更新数据库状态后如何立即同步你的状态是一个问题,另一方面,如果它太短,就会出现网络流量问题。如果您能给我一些建议,我愿意接受该解决方案 [另外,请参阅我的编辑]
    • 推送并不完全意味着长轮询。如果你使用 LCDS,它使用的是实时推送信息的 RTMP 协议。然而,长轮询在过去对我来说效果很好,前端的工作很少,后端的工作更多。我相信您可以在网上找到有关投票时间的文档。
    【解决方案3】:

    查看“dpHibernate”项目。它在 Flex 客户端上实现了“延迟加载”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-21
      • 2020-02-16
      • 2011-03-26
      • 2023-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多