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