【问题标题】:RequestFactoryEditorDriver getting edited data after flushRequestFactoryEditorDriver 在刷新后获取已编辑的数据
【发布时间】:2012-03-20 15:35:26
【问题描述】:

让我从我有一个解决方案开始,但我真的不认为它很优雅。所以,我正在寻找一种更清洁的方法来做到这一点。

我在视图面板中显示了一个 EntityProxy。视图面板是仅使用显示模式的 RequestFactoryEditorDriver。用户单击数据元素并打开弹出式编辑器以编辑 EntityProxy 的数据元素,其中的数据位比视图面板中显示的数据位多。当用户保存元素时,我需要视图面板来更新显示。

我遇到了一个问题,因为弹出编辑器流程的 RequestFactoryEditorDriver 不允许您访问已编辑的数据。驱动程序使用与您用于向服务器发送数据的上下文相同的传递上下文,但是从刷新返回的上下文仅允许 Receiver<Void> 即使您将其转换为您在编辑器中存储在编辑器驱动程序中的上下文类型( ) 称呼。 [它似乎也没有发送 EntityProxyChanged 事件,所以我无法监听并更新显示视图。 - 从头开始​​ - 我现在看到这个事件不适合这个用例]

我找到的解决方案是更改我的域对象持久性以返回新保存的实体。然后像这样创建弹出编辑器

editor.getSaveButtonClickHandler().addClickHandler(createSaveHandler(driver, editor));
                // initialize the Driver and edit the given text.
                driver.initialize(rf, editor);
                PlayerProfileCtx ctx = rf.playerProfile();
                ctx.persist().using(playerProfile).with(driver.getPaths())                      
                        .to(new Receiver<PlayerProfileProxy>(){
                    @Override
                    public void onSuccess(PlayerProfileProxy profile) {
                        editor.hide();
                        playerProfile = profile;
                        viewDriver.display(playerProfile);
                    }                               
                });
                driver.edit(playerProfile, ctx);
                editor.centerAndShow();

然后在保存处理程序中,我只是触发()从flush()获得的上下文。虽然这种方法有效,但似乎并不正确。 [看来我应该订阅显示视图中的 entitychanged 事件并从那里更新实体和视图。 - 再次从头开始,与之前的原因相同 ] 此外,这种方法保存了完整的实体,而不仅仅是更改的位,这将增加带宽使用。

我认为应该发生的是,当您刷新实体时,它应该“乐观地”更新实体的 rf 托管版本并触发实体代理更改事件。只有在保存中出现问题时才恢复实体。实际保存应该只发送更改的位。通过这种方式,不需要重新获取整个实体并通过线路两次发送完整的数据。

有没有更好的解决方案?

【问题讨论】:

    标签: gwt requestfactory


    【解决方案1】:

    您似乎并不真正了解射频发生的细节;另外,您的术语并不能真正帮助理解(冲洗与火灾)。

    RF 中的代理是您检索时服务器状态的快照。您可以在应用程序的其他地方(通过其他代理)对实体做任何您想做的事情,您的代理永远不会改变以反映这些修改。

    EntityProxyChange 事件在服务器检测到它已更改时在客户端(对于服务器已知并已从客户端发送的实体)调度:其版本(如返回getVersion 上的 Locator) 已更改,或者已被删除(如 LocatorisLive 方法所述)。如果您不使用Locator,它将使用实体的getVersion,并且isLive 将被find 替换为实体的ID(由其getId 方法返回)和检查null(这也是LocatorisLive的默认实现)。
    在您的情况下,如果您没有看到 EntityProxyChange 被分派,请检查您是否正确更新了实体的版本。

    最后,RF 总是将您的更改的差异发送到服务器(ValueProxy 除外,在这种情况下差异将没有任何意义)。至于检索数据,默认情况下它不会检索链接代理,除非您使用with 明确要求它们;这与您可能发送的有关实体的信息无关。

    在您的情况下,要更新 视图面板,您有 3 种可能性:

    • 从服务器取回代理(侦听EntityProxyChange 事件或在弹出窗口发出显式信号后;您可以使用RequestContextfind 方法和代理的stableId 作为参数,并使用适当的with 用于您需要的属性)。
      当您执行第二个 HTTP 请求时,它的效率有点低,但另一方面,它可以处理应用程序中其他地方的更改(它们也会触发 EntityProxyChange 事件)
    • 在与保存它的请求相同的 HTTP 请求中检索更新的代理:让请求上下文的 save 方法返回已保存的实体,或在同一请求上下文中调用 find 方法以 batch savefind 在同一个 HTTP 请求中一起处理。
      这就是你所做的。它发送更改的差异并检索视图面板所需的属性。可以说它的缺点是弹出窗口和视图面板紧密耦合,这是否是一种可接受的权衡取舍取决于您。
    • 直接在视图面板中使用您编辑并发送到服务器的实体,无需通过网络传输额外数据。
      虽然这看起来更简单,但您会错过其他用户可能对实体所做的任何更改(只有服务器知道的更改)。

    总而言之,我想我会采用当前的解决方案。不过,关于您的代码,我会启动带有代理和回调的弹出窗口,并将请求上下文和编辑编辑器驱动程序保留为弹出窗口的实现细节:您只需要它调用视图面板完成后返回,将更新后的代理作为参数传递给回调。

    关于术语的最后一句话:您刷新编辑器驱动程序以将字段的值复制回对象/代理,并且(独立地,但在您的情况下按顺序)您触发 em> 向服务器发送一批服务方法和代理更改的请求上下文。刷新编辑器驱动程序不会向服务器发送任何内容,这些是不同的操作。

    【讨论】:

    • 感谢您的回答,但我不确定您认为我在哪里混淆了冲洗和开火。我完全按照您的描述使用它们。同样在 RequestFactoryEditorDriver flush 返回您初始化它的 rf 上下文,而不是编辑的对象,这会阻止您的第三个选项成为可能(除非有一些我没有找到的访问器)。还查看发送的 http 请求,整个实体被发送到服务器,而不仅仅是 delta 的 - 这与记录 rf 的方式不同。当 EntityProxyChange 事件是条件时,您给出的条件是...
    • 我考虑过您的选项 1,但正如您所说,这是到服务器的额外往返行程。我使用了选项 2,但它没有按预期工作,因为它不发送差异。在此过程开始之前,实体已经存在于服务器上并被提取到视图面板中。那就是我在示例代码中引用的 playerProfile。我用它来初始化 RequestFactoryEditorDriver,所以我希望在驱动程序刷新和/或更新原始代理时触发一个事件(eventbus fire not rf)。我是否错过了阻止这些事情发生的事情?
    • 另外,我没有完全理解 entityproxy 的用例,当你抓住它时它只是一个快照。你是对的。我认为它更像是一个实体的远程/客户端副本,如果我从服务器获取同一实体的新副本并发送一个 entityproxychange 事件,它将被更新。
    • 我希望我可以编辑 cmets - 所以放弃关于事件不触发的所有内容 - 我现在了解它触发时的限制。如果我们需要客户端通知客户端何时更改代理,我想我们必须自己滚动。这看起来确实应该在 RF 中,至少在添加缓存时是这样。我仍然不知道为什么它会发送完整的实体而不是差异。
    • 我似乎找到了另一个原因 EntityProxyChange 事件没有触发。版本号在数据库中没有增加。我正在使用 JPA,并且有一个已知的错误 code.google.com/p/google-web-toolkit/issues/detail?id=6712 会阻止任何 RF 实例请求在没有额外完整实体副本的情况下增加版本 [ 意思不是仅仅保留实例,而是执行 em.find(... ) 将当前实例数据从数据库复制到实例,然后将数据库中的数据持久化。那只是为了让版本增加。
    【解决方案2】:

    我找到了更好的解决方案。我在调用 RequestFactoryEditorDriver edit() 之前使代理可编辑,并将可编辑代理保存为我的视图代理。

    PlayerProfileCtx ctx = rf.playerProfile();
    playerProfile = ctx.edit(playerProfile);
    driver.edit(playerProfile, ctx);
    

    另外,(我以为我之前已经尝试过,但它没有工作,但我一定做错了什么)我可以投射从刷新中返回的上下文。这与我通过 edit() 调用发送给驱动程序的上下文相同,因此它是安全的。

    PlayerProfileCtx ctx  = (PlayerProfileCtx) driver.flush();
    

    这样做解决了 rf 使用 fire() 发送整个对象而不仅仅是差异的问题。我不确定为什么。这可能是 RF 编辑器驱动程序中的一个错误。

    所以现在我已经在视图中获得了来自驱动程序的数据,并且不必依赖于从服务器发回数据。但我确实注册了 EntityProxyChange 事件,因此如果服务器上存在冲突,我可以检测并重新获取。

    【讨论】:

      猜你喜欢
      • 2020-06-17
      • 2023-01-31
      • 2016-11-14
      • 1970-01-01
      • 2012-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-12
      相关资源
      最近更新 更多