【问题标题】:How do I update an OData entity and modify its navigation properties in one request?如何在一个请求中更新 OData 实体并修改其导航属性?
【发布时间】:2012-09-26 14:59:09
【问题描述】:

我正在尝试使用 WCF 数据服务提供的 OData 服务(目前使用 OData V3 application/json;odata=verbose 有效负载格式)来实现我认为的简单场景。我可以使用 JSON Light 格式未来)。基本场景是这样的:

我有两个实体:

class Person 
{ 
  public int ID { get; set; }
  public string Name { get; set; } 
  public virtual PersonCategory Category { get; set; }
}

class PersonCategory
{
  public int ID { get; set; }
  public string Description { get; set; }
  public virtual ICollection<Person> People { get; set; }
}

现在,我想为 Person 创建一个简单的编辑页面。这个编辑页面可能有一个名称输入,以及一个人的类别的输入或下拉列表。

所以,场景是这样的:

  1. 代码使用 $expand 为类别下载人员:GET /api.svc/People(1)?$expand=Category
  2. 用户编辑人员的姓名属性及其类别。
  3. 页面代码发出单个请求以更新该人员的姓名和类别属性。

这里的关键在于“单个请求”。这是我找不到文档的部分。我见过他们将上面的数字 3 分成两个请求的例子。像这样的东西(我不记得确切的格式 - 我也不确定您是否必须在执行 PUT 之前删除类别链接):

PATCH /api.svc/People(1) with content: {"Name": "new name" }
PUT /api.svc/People(1)/$links/Category with content: { "url": "/api.svc/Categories(2)" }

但是,我也听说过,但没有证明,可以通过对 Category 导航属性的更改与对 Person 实体的其他更改一起指定的单个请求来实现此更新。有人可以给我一个如何做到这一点的例子吗?另外,你能告诉我如何使用多对多导航属性来完成,而不是我上面描述的一对多。

最后,我目前使用的是详细的 JSON 格式,V3。如果我改用新的 JSON 灯光格式,您对上述问题的回答会不会有所不同?如果有,怎么做?

【问题讨论】:

  • 您可以发送一个批处理请求 - 这将是一个包含两个操作的单个请求。
  • 除了批量请求之外,没有其他方法可以做到这一点吗?这会给客户端的往返代码增加一些额外的复杂性,我希望避免这种复杂性。理想情况下,我只想将我的 PATCH /api/Activity(1) 请求格式化为: {"category": { "__deferred" : { "uri": "/api.svc/Categories(2)" } }} 但是,这似乎不起作用。我收到 204 响应,但服务器端的属性保持不变。
  • WCF 数据服务不支持所谓的深度更新(这是您想要的)。事实上,甚至 OData 本身也没有真正定义它。在某些情况下,它的含义可能会变得相当复杂。恐怕批处理是唯一的解决方案。虽然支持深度插入(但同样仅插入,不修改任何现有内容)。
  • 问题:是要更新分类实例还是要更新分类实例的某些属性。除了批处理之外,没有其他方法可以做后面的事情。对于前者,您可以执行以下操作:{ "Name" : "new name", "Category" : { "__metadata" : { "uri" : "/api.svc/Categories(2)" }}}。希望这会有所帮助。
  • 抱歉回复晚了。是的,前一个。我不想更新类别实例的属性 - 只需将 Person 实例的类别更新为不同的类别。

标签: json wcf-data-services odata


【解决方案1】:

我发现了两种内联表示导航属性的方法:

application/json;odata=verbose - { "Name": "new name", "Category": { "__metadata": { "uri": "Categories(2)" }}}

application/json - { "Name": "new name", "Category@odata.bind": "Categories(2)" }

【讨论】:

  • 您的第一个示例是 OData 3.0 规范。你的第二个是 OData 4.0
【解决方案2】:

Pratik 的评论就是答案(Pratik 如果您想将此作为答案重新发布,我会这样标记 - 谢谢!):

问题:您要更新类别实例还是要更新类别实例的某些属性。除了批处理之外,没有其他方法可以做后面的事情。对于前者,您可以执行以下操作:{ "Name" : "new name", "Category" : { "__metadata" : { "uri" : "/api.svc/Categories(2)" }}}。希望这可以帮助。 ——普拉蒂克

【讨论】:

  • 嗯,当我使用完整的 url\uri 作为链接元数据时,嗯,好吧。
【解决方案3】:

您不再需要批次了。您可以在一个电话中完成。您只需要同时发送更改的属性并让存储库处理更改的属性。

public class Person 
{
   public string FirstName {get;set;}
   public string LastName {get;set;}
   public int Age {get;set;}
}

假设您注意到名字有错字,Jhon,应该是 John。您可以编辑名字并将其发送出去。所以你有以下对象模型。您可以通过以下两种方式之一获得此信息:

  • 有两个参数并设置BodyStyle = WebMessageBodyStyle.Wrapped
  • 只需创建一个具有两个属性的通用模型对象:属性 1 是类型 T,属性 2 是列表。

所以你会发送这个json:

[{ FirstName = 'John' }, ['FirstName']]

现在在服务器端,你可以做你需要做的事情了。

如果您不想发送更改的属性,您可以通过选择值不是默认属性的任何属性来猜测更改的属性。

{ 名字 = '约翰' }

然后你可以使用几个方法来查看哪些属性发生了变化:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-27
    • 2012-05-19
    • 1970-01-01
    • 2020-11-04
    • 2018-08-30
    • 1970-01-01
    • 1970-01-01
    • 2017-03-17
    相关资源
    最近更新 更多