2014-11-08 61 views
1

在我的Web应用程序中,我有产品和购物清单。该服务器提供REST端点。Ember数据的增量更改多对多关系

GET /api/shopping-lists/abc 

回报

{ 
    shoppingList: { 
    id: "abc", 
    products: ["p123", "p234", "p345"] 
    } 
} 

在我Ember 1.7.0的应用程序,我用Ember Data 1.0.0-beta.6。我的模型是这样的:

App.ShoppingList = DS.Model.extend({ 
    products: DS.hasMany("product", {async: true}), 
}); 

App.Product = DS.Model.extend({ 
    name: DS.attr("string") 
}); 

,因为我无法找到从许多一对多的关系添加和删除记录,我添加和删除产品/右侧的“灰烬办法”规范的信息从购物清单是这样的:

function addToShoppingList(shoppingList, toBeAddedProduct) { 

    shoppingList.get("products").then(function(products) { 
     products.pushObject(toBeAddedProduct); 
     shoppingList.save(); 
    }); 

} 


function removeFromShoppingList(shoppingList, toBeRemovedProduct) { 

    shoppingList.get("products").then(function(products) { 
     products.removeObject(toBeRemovedProduct); 
     shoppingList.save(); 
    }); 

} 

目前上述函数调用shoppingList.save(),灰烬数据会发送一个请求,PUT用JSON的有效载荷包括该购物清单上的所有产品编号:

addToShoppingList(abcShoppingList, p456Product); 

//results in PUT on /api/shopping-lists/abc with payload: 
{ 
    "shoppingList" : { 
     "products" : ["p123", "p234", "p345", "p456"] 
    } 
} 

如购物清单可以变得很长,我宁愿希望有只增量更新只包括购物清单的变化,即:

{ 
    "shoppingList" : { 
     "products" : ["p456"] 
    } 
} 

我可以灰烬数据只PUT对记录的更改,而不是发送完整记录?

此外,removeFromShoppingList(..)函数将发送完整记录作为PUT请求。相反,我宁愿让它发送增量DELETE请求。

+0

不,你不能。这是唯一一次保存shoppingList模型吗? – Kingpin2k 2014-11-08 17:17:32

+0

@ Kingpin2k,'addToShoppingList(..)'和'removeFromShoppingList(..)'是我的代码中唯一可以修改'ShoppingList'的'products'关系的地方。我一直在考虑在不依赖Ember Data的情况下自己照顾自定义请求和记录更新,但我会猜测Ember Data带来了这种功能... – Abdull 2014-11-08 17:26:24

+1

只需手动处理它,会更容易。我不知道任何其他客户端ORM是否像您正在谈论的那样进行增量更新。 – Kingpin2k 2014-11-08 18:21:57

回答

1

Ember Data允许您实现无论您需要在适当的模型序列化器中以及适配器中构建JSON有效负载(如果需要的话)。我建议查看JSONSerializer和RESTSerializer的Ember数据源代码,因为调优生成(序列化)和使用(规格化)的JSON具有巨大的灵活性。

听起来你想要实现PATCH语义,但是你可以用PUT做你想做的事情,提供你的URL端点仅仅关注产品关系,例如/api/shopping-lists/123/products。这与针对完整模型/api/shopping-lists/123以及仅对“产品”数组进行PUTing不同,因为它不符合HTTP语义。

一个URL标识一个资源,并且该端点上的GET和PUT或DELETE可以idempotently更新或删除一个属性或值的一个子集,只要该URL范围为该属性或某个子集,它就是根据定义,一个独特的资源和HTTP完全支持重叠的资源,甚至是受PUT影响的多个资源。

因此,您可以进一步将购物清单中的产品表示为单独的资源:/api/shopping-lists/123/:product-id,只需使用DELETE删除并PUT创建/添加产品到列表。许多网址设计都是可能的,包括所示的嵌套网址,或者使用复合键甚至代理键,因此您必须考虑服务器上的最佳效果。

您可能决定实施Ember Data连接模型,例如ShoppingListProduct以使其更容易管理。 ShoppingListProduct将为ShoppingList和Product指定belongsTo关系。您还可以从两个belongsTo关系中制作'id'属性,以便DS Store标识映射按预期工作。这在你的模型序列化器中实现是微不足道的。

UPDATE

要回答下面一个很好的规律可循您的评论是想PUT作为替换,而不是更新,让你放什么是你应该得到的是什么假设没有其他已修改的资源自从你的PUT。如果不是这样,它可能表示您没有为您的URL定义足够精细的粒度来限定您要替换的内容,或者您​​可能应该考虑使用PATCH来定位您想要更改的属性。

我不知道本身是否有“最佳实践”,但我倾向于只从具有外键的端点(即belongsTo端)更新资源。多对多的关系,我通常最终与一个连接资源,例如标签或友谊,所以它只是通过belongsTo管理关系。这往往会遵循你在关系数据库中做的事情,所以它运行良好。

+0

很棒的回答。我想知道在资源之间添加和删除*关系的正确RESTful方式是什么。 'PATCH'似乎增加了一个额外的方法... P.S .:为什么''在'/ api/shopping-lists/123'上放弃'产品'植根的JSON有效负载? – Abdull 2014-11-10 09:58:53

+1

更新答案,提供关于管理关系和REST/PUT的一些指导 – 2014-11-10 13:04:12