swb*_*dit 3 rest updates servicestack
使用 ServiceStack(面向消息的 RESTful Web 服务)实现对象属性更新的正确方法是什么?
如果客户端需要更新 Foo.bar 并且只有 Foo 的 id。
我应该接受包含 Foo id 和 Foo.bar 值的 FooBarUpdate 请求对象吗?这意味着我必须为每个属性更新创建单独的请求,或者至少为那些我希望更新的请求(或它们的组合)。这似乎也不符合 RESTful 标准。
或者,如果我接受包含具有更新属性的整个 Foo 的 Foo 请求对象,客户端将首先需要检索 Foo,然后服务将检查哪些属性已更新。这似乎是不必要的开销。
最后,如果我接受 Foo 请求但只有 id 和修改后的属性值 (Foo.bar),则 Foo 对象是不完整的,根据其他帖子,这可能会导致混淆,有人认为它是一个完整的对象。
如果Bar是一个单独的属性,Foo那么你没有理由不能只拥有一个UpdateFooRequest包含更新的Bar.
像这样:
[Route("/foo/{Id}", "POST")]
public class UpdateFooRequest
{
public int Id { get; set; }
public Bar Bar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
但是,如果Bar是一个集合使得 Foo 是:
public class Foo
{
public int Id { get; set; }
public Bar[] Bar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后更新Bar项目的更安静的方法Foo是bar通过Foo路由引用实例。但是您需要知道 bar 的 id,(或集合中相对于它的索引Foo)。
[Route("/foo/{FooId}/bar/{Id}", "POST")]
public class UpdateFooBarRequest : Bar
{
public int FooId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
为了解决这些问题:
或者,如果我接受一个
Foo请求对象,该对象包含具有更新属性的整个 Foo,客户端将首先需要检索 Foo,然后服务将检查哪些属性已更新。这似乎是不必要的开销。
你唯一需要关心一个整体的时间Foo是什么时候Foo被创建,它会有自己的路线。所以这里应该没什么好担心的。
[Route("/foo", "POST")]
public class CreateFooRequest
{
...
}
Run Code Online (Sandbox Code Playgroud)
当Foo正在更新你将张贴到这样一个现有的富路线/foo/123:
[Route("/foo/{Id}", "POST")]
public class UpdateFooRequest
{
public int Id { get; set; }
...
}
Run Code Online (Sandbox Code Playgroud)
最终,您的服务应该能够指示 ORM 仅更新包含在请求中的字段的更改。因此,如果请求只有几个更改,那么 ORM 将处理它。
例如,ORMLite 更新很简单:
db.Update<Foo>(updateFooRequest);
Run Code Online (Sandbox Code Playgroud)
这将UPDATE在Id仅使用请求中找到的字段标识的行上创建 SQL ;
如果Foo发送了一个整体,然后允许 ORM 将其视为更改了许多字段,则该记录将被覆盖。您可以按照您的建议在更新之前查找记录并确定更改的字段,但正如您所说,这是不必要的开销。
通常,如果您的更新方法处理部分更改,那么发送整体Foo应该没有问题,但理想情况下,客户端应该只发送更改。
最后,如果我接受 Foo 请求但只有 id 和修改后的属性值 (Foo.bar),则 Foo 对象是不完整的,根据其他帖子,这可能会导致混淆,有人认为它是一个完整的对象。
最后一行where someone assumes it's a full object,有点令人担忧。update 路由应该只用于更新,你不应该在这里使用完整的对象。update 方法应该期望请求Foo是部分的,并且按照我上面的解释进行处理。
我认为您可能应该阅读 ORMLite,它展示了一些很好的示例,说明如何将部分更新应用于现有数据。虽然您不必选择 ORM,但基本概念适用于其他 ORM,我认为这很好地说明了它们。
要按名称更新Bar集合中的项目Foo:
这样做是非常规的。使用有意义的值(例如 Name)的一个缺点是您将无法轻松更改此属性 - 因为它是一个标识符。如果它是静态的,那就没问题了。
所以Foo看起来像这样:
public class Foo
{
public int Id { get; set; }
public Bar[] Bar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
让我们假设 Bar
public class Bar
{
public int Id { get; set; }
public string Name { get; set; }
public int Baz { get; set; }
public bool IsEnabled { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
如果我使用Name而不是IdBar 来更新,我将无法更改该Name属性,因为那时我不知道要更新哪个 Bar。我现在需要一条全新的路线来处理更改 Bar 的名称。
如果您决定将其用作集合中的标识符,您可以执行以下操作:
[Route("/foo/{FooId}/bar/{Name}", "POST")]
public class UpdateFooBarRequest : Bar
{
public int FooId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
因此,要更新美孚123的更新Baz = 13,并IsEnabled = false在酒吧名为“鲍勃”
POST /foo/123/bar/Bob
{
Baz: 13,
IsEnabled: false
}
Run Code Online (Sandbox Code Playgroud)
在您的操作方法中,您只需要更新与名称“Bob”匹配的 Foo 为 123 的项目。在 ORMLite 中,它看起来像这样:
db.Update(updateBarRequest, p => p.FooId == updateBarRequest.FooId && p.Name == updateBarRequest.Name);
Run Code Online (Sandbox Code Playgroud)
但这样做意味着你不能这样做:
[Route("/foo/{FooId}/bar/{Id}", "POST")]并且[Route("/foo/{FooId}/bar/{Name}", "POST")]因为路由器不知道您是否正在传递一个Id或一个Name所以所以您必须执行非常规的 REST 之类的[Route("/foo/{FooId}/bar/byName-{Name}", "POST")].
我希望这有帮助。
| 归档时间: |
|
| 查看次数: |
2929 次 |
| 最近记录: |