v2.ODataModel:哪个API更受欢迎? "bindElement" 还是 "read"?

v2.ODataModel: which API is more preferred? "bindElement" or "read"?

我设置 view.setModel(model),获取视图的模型,并请求 model.read("/entitySet('10000')")。 然后用 /entitySet('10000')/properties.

填充模型

但是很难将它们分配给视图字段,因为现在在视图中,<Text text="{property}"> 不起作用。必须是 <Text text="{/entitySet('10000')/property}">.

另一方面,如果我将视图的上下文绑定设置为 "/entitySet('10000')",那么 <Text text="{property}"> 将开始工作。

首选哪种方法?什么时候使用 .read?

如果我想直接在绑定上下文中使用 OData 调用的结果,我几乎从不使用 .read。我使用 .read 的唯一一次是如果我想在对结果做任何事情之前操纵结果。

例如从sdk看这个例子:https://ui5.sap.com/#/entity/sap.ui.table.Table/sample/sap.ui.table.sample.OData

这种绑定的语法与 read 类似,但在事件和一些不同类型的方法上存在一些差异,具体取决于您要绑定的内容。例如绑定到视图使用 bindElement:

 this.getView().bindElement("/entitySet('1000')");

在此之后,该特定实体 上的字段可以 作为 <Text text="{property}" /> 访问。

这是我当前的一个应用程序的示例,其中包含事件和其他一些调用参数:

this.getView().bindElement({
  path: `/Orders('${currentOrderNumber}')`,
  parameters: {
    expand: 'Texts'
  },
  events: {
    dataRequested: _ => this.getView().setBusy(true),
    dataReceived: data => {
      if (!this.getView().getBindingContext()) {
        // navigate to `Not Found` view
      }
    },
    change: _ => this.getView().setBusy(false)
  }
});

对于table,它略有不同,因为它取决于您希望绑定的聚合,例如

oTable.bindRows({
  path: "properties"
});

与以下相同:

<Table rows="{properties}" />

我几乎同意 Jorg 的观点,但不完全同意:

这实际上取决于您要实现的目标。如果希望从后端显示数据,那么最简单的方法是使用 this.getView().bindElement()

但是如果您需要在显示之前操作数据(例如格式化文本、显示来自 base64 字符串的图像等)或者如果您想使用一些现有数据创建新实体,或者更新现有数据 - this.getModel(sName).read() 是要走的路 - 因为您可以在 successCallback 中将读取实体及其所有深层实体设置为 JSONModel 并从 localModel 对其进行操作。

如果使用 localModel,则 dataBinding 在视图中几乎相同 - 除了您必须另外提供模型名称以从中获取数据。因此,例如,如果在 Model.read() 的 successCallback 中将数据设置为名为 "localModel" 的模型:

this.getModel().read(sObjectPath, {
            urlParameters: {
                $expand: ""
            },
            success: function (oData) {
              // "localModel" is name you gave in onInit function to your new JSONMOdel, when setting it to View e.g. this.getView().setModel(oJSONMOdel, "localModel")
               this.getModel("localModel").setData(oData);
            } 
          })

然后在 XML 视图中你会指出

<Text text="{localModel>/mainPropertyName}"/>
// for displaying deep entities as List items or in Table
<List items="{localModel>/deepEntityName}">
 <StandardListItem title="{localModel>propertyNamefromDeepEntity}" />
</List>

根据我使用更复杂的应用程序的经验,Read-Only - 我总是使用 Model.read()。

更具表现力总是很重要的。使用专为执行该任务而设计的 API。

比较两个变体:

  1. myModel.read(<em>sPath</em>)text="{/path/property}"
  2. myControl.bindElement(<em>sPath</em>)text="{property}"

我会对第一次调用感到困惑,而在第二次调用中,我会确切地知道你想要实现什么(你想要绑定元素。或者,bindObject也可以用)。

框架也是如此。由于您准确地说明了您想要实现的目标,因此该框架可以根据您的意图改进其行为。 例如:(route)PatternMatched 处理程序中,当用户导航到同一页面时,具有相同路径的 .bindElement 不会触发另一个请求,因为模型已经存储了实体从以前的电话。它可以立即显示结果。
然而,使用 .read,框架不知道你想要实现什么,所以它会立即发送请求,而不管应用程序状态如何。

此外,第一个变体不是 future-proof。它依赖于缓存的结果。它几乎是一个 side-effect 它的工作原理。问题是不能保证这种行为在以后的版本中会继续有效。另外 V4 ODataModel 中不会有 read 方法。


TL;DR

v2.ODataModel#read

  • 不会从响应创建context。重复 .read("<same path>") 总是发送一个新的请求。
  • 表达能力差。鼓励应用开发者使用 client-side 模型(例如 JSONModel)。
  • 应用程序失去上下文感知,增加 TCO,减少 future-proof。

bindElement or bindObject

  • 根据响应创建 context 并将其存储在内部,以便同一请求可以立即 return 数据。
  • 明确表达意图;应用程序和框架可以使用现有的 APIs.
  • 更多future-proof:<strong>v4.</strong>ODataModel支持手动读取.想象一下,您已经使用 v2ODataModel.read-jsonModel.setData 方法构建了您的应用程序,并且您需要迁移到 v4。玩得开心。 :)


老实说,我认为 v2.ODataModel#read 永远不应该成为 public 方法。我不鼓励任何人在手动读取 $count 值时使用 .read except of

如果实体值需要格式化,有开箱即用的格式化程序和绑定类型,也很容易扩展。

如果应用程序需要重构响应主体,通常是数据模型设计不当或服务不符合 OData 规范的标志。