【发布时间】:2022-01-13 12:47:47
【问题描述】:
如何将实体发布到 OData 端点,同时将其与正文中的其他现有实体关联?
考虑以下类结构(示例):
class Invoice
{
public int Id { get; set; }
public Person Issuer { get; set; }
public Person Recipient { get; set; }
// other properties
}
class Person
{
public int Id { get; set; }
// other properties
}
Invoice 和 Person 都是我域中的实体(因此是 Id 属性)。想象一下,两者都暴露在自己的实体集中,所以:
-
GET http://host/odata/People(1)返回
Person和Id = 1 -
GET http://host/odata/Invoices(2)?$expand='Issuer, Recipient'返回
Invoice和Id = 2,Issuer和Recipient在有效负载中展开
现在考虑以下要求:
我想在系统中创建一张新发票,该发票将与现有的发卡人和收件人相关联
如何“告诉”OData 框架我要将给定的导航属性与现有实体相关联?如何通知我的控制器操作这是意图?
理想情况下,我希望 POST 正文看起来像这样:
-
POST http://host/odata/Invoices{ "发行人": "/odata/People(1)", "收件人": "/odata/People(2)", "Property1": "someValue", “属性 2”:“100”, ... }
一旦服务器收到此有效负载,它应该:
- 为
Issuer属性加载所需的“people(1)”Person。如果不存在,则应返回错误请求。 - 为
Recipient属性加载所需的“people(2)”Person。如果不存在,则应返回错误请求。 - 创建一个新的
Invoice实例并从上面分配Issuer和Recipient,然后将其保存到数据库中。
我知道 OData 支持使用 entity/relation/$ref 语法使用特殊的 PUT/POST URL 在事后配置关系。有了这样的语法,我就可以做这样的事情:
-
POST http://host/odata/Invoices{ "Property1": "someValue", "Property2": "100" } -
PUT http://host/odata/Invoices(x)/Issuer/$ref{"@odata.id":"http://host/odata/People(1)"} -
PUT http://host/odata/Invoices(x)/Recipient/$ref{"@odata.id":"http://host/odata/People(2)"}
但是,我希望能够在一个应该以原子方式创建实例的 POST 操作中执行所有这些操作。
我尝试了一些想法来看看服务器会接受什么,这似乎通过了:
{
"Issuer": { "@odata.id": "/odata/People(1)" },
"Recipient": { "@odata.id": "/odata/People(2)" },
"Property1": "someValue",
"Property2": "100",
...
}
但我不知道我如何能够从中读取/解析 ID(例如它是如何在专用的 Ref 方法中完成的),或者即使 OData 标准支持这一点。
现在,我将仅在模型和服务器中传递 ID 属性,假设这总是意味着存在关系,但这远非理想,因为它不够通用,并且会使我的 API 不灵活。
【问题讨论】:
-
您可以使用服务批处理端点发送批处理请求。有关批处理如何在此处工作的更多详细信息odata.org/documentation/odata-version-3-0/batch-processing
-
如果请求来自 .NET OData 客户端 docs.microsoft.com/en-us/odata/client/batch-operations,请查看此链接
-
@JohnGathogo 我知道 OData 中的批处理支持,但现在,我希望服务器上的操作是事务性的:即,我不想仅插入
Invoice实体发现我无法将它与Issuer或Recipient关联。在 POST 中的单个事务中执行所有这些可以让我更强大的数据完整性并简化客户端,因为它不必处理这些极端情况。批处理请求通常是相互独立的,所以我认为这不太合适。 -
“批处理请求通常是相互独立的,所以我认为这不太合适”——这种说法并不完全正确。如果您从客户端发送请求并调用
SaveChanges或SaveChangesAsync并使用SaveChangesOptions.BatchWithSingleChangeset作为参数,它保证您是一个事务。 -
而且单次批处理并不局限于使用OData客户端时。如果您通过此链接odata.org/documentation/odata-version-3-0/batch-processing,您将在示例中看到如何使用批处理和变更集。变更集是一个原子工作单元。这是我实际使用过的东西
标签: c# odata asp.net-core-webapi odata-v4