Ember Data不允许在hasMany关系中存在重复条目

9

我有以下这个模型:

#order/model.coffee
Order = DS.Model.extend {
  line_items: DS.hasMany 'product', {async: true}
}

在某些时候,我想向订单中添加一些产品。我发现我只能添加一次产品,再次添加相同的产品无效:

#product/route.coffee
...
actions:
    # Not actually my code but illustrates the problem
    addToCart: (product1, product2)->
      order = @modelFor 'order'
      console.log order.get('line_items.length') # prints 0

      order.get('line_items').pushObject product1
      console.log order.get('line_items.length') # prints 1

      order.get('line_items').pushObject product2
      console.log order.get('line_items.length') # prints 2

      order.get('line_items').pushObject product1
      console.log order.get('line_items.length') # prints 2

      order.get('line_items').pushObject product2
      console.log order.get('line_items.length') # prints 2


      ...

问题在于用户可能想要多次获取单个项目。最简单的表示方法是使用带有重复条目的数组。似乎Ember不允许我在关系中这样做。如何使一个模型多次添加到关系中?


应该使用hasMany('product'),而不是'products'。 - Christopher Milne
@ChristopherMilne,将“products”更正为“product”,结果相同。出于简洁起见,我省略了订单来源,但它是从服务器的其他地方检索到的现有订单。我很确定我正在检查实际数组。无论如何,序列化为JSON的数组仅包含一个项目。 - jd.
你确定要使用Ember Data关系来完成这个吗?如果这是一个电子商务网站,用户完成订单后,一年后您检索订单记录时,产品模型已经发生了变化,那么订单是否仍然准确无误呢? - Christopher Milne
我会保存产品的变更数组,因此您可以随时将其重构为先前的状态。所以是的。但这不是这个问题的重点。 - jd.
下面的“行项目”模型是正确的解决方案。如果您不想要一个数量字段,您可以有没有数量的OrderItem,并且只需为相同的产品重复OrderItems。然后,您将拥有与orderitems的toMany关系,即使表示相同的产品,每个订单项也将是唯一的。 - shaunc
显示剩余2条评论
2个回答

4

听起来你实际上需要一个带有数量字段的line_items模型。只是把更多相同的物品塞进你的orders模型并不是一个真正规范化的解决方案。

我建议采用以下方法:

lineItem = DS.Model.extend({
    orders: DS.belongsTo('orders'),
    product: DS.belongsTo('products'),
    quantity: DS.attr('number'),
});

orders = DS.Model.extend({
    lineItems: DS.hasMany('lineItem', {async: true}),
    customerId: DS.belongsTo('customers'),
});

products = DS.Model.extend({
    title: DS.attr('string'),
    description: DS.attr('string'),
    cost: DS.attr('string'),
});

这将允许您在lineItem模型中创建多个记录,这些记录将具有唯一的ID,但绑定到特定订单(这将解决多个订单具有相同lineItem的问题)。例如,您可以拥有以下内容:
{
    "lineItem" : 
        [
            {
                "id": 1,
                "orderId": 1,
                "product": 1,
                "quantity": 100,
            },
            {
                "id": 2,
                "orderId": 1,
                "product": 2,
                "quantity": 10,
            },
            {
                "id": 3,
                "orderId": 2,
                "product": 1,
                "quantity": 100,
            }
        ]
}

在这种设计中,您需要从您的JSON中删除对lineItems的引用,因为Ember-data会为您处理反向关系(如果您没有将关系侧载,则需要在您的模型中添加async)。这意味着如果您需要更改行项目,它只会影响一个订单,如果您需要更改与之相关的行项目的订单,则只需在lineItem模型上执行此操作。
{
    "Orders" : 
        [
            {
                "id": 1,
                "customerId": 123456,
            },
            {
                "id": 2,
                "customerId": 123456,
            }
        ]
}

我的问题是我需要为lineItem模型构建服务器端支持(生成每个line Item的唯一ID,否则Ember Data会混淆)。这对于本应该非常简单的事情来说是一个巨大的开销。我希望有一种方法可以实现无ID嵌入式关系。 - jd.
在数据库中使模型中的记录重复将形成多对多关系。这不是规范化的,这就是为什么Ember不喜欢你这样做的原因。据我所见,添加lineitem模型是规范化的方法。从未来查询的角度来看,这是最有意义的。例如,如果您想知道最受欢迎的产品,则只需对包含该产品ID的lineitems数量进行求和即可。 - Phil Hauser
这确实是一个多对多的关系,因为订单有很多产品,而产品可以在很多订单中。那么你会设计一个单独的端点 /line-items 来允许 CRUD 方法吗?然后几个订单将被允许共享相同的行项目,这是没有意义的,因为在某个地方修改它将修改所有订单。 - jd.
关于CRUD端点,你提出了一个很好的观点。我已经更新了答案来处理这个问题。 - Phil Hauser
我明白你的意思,但我仍然觉得这种解决方案的开销很大(单独的表格,为新模型单独的CRUD端点)。更糟糕的是,我正在使用NoSQL数据库,因此嵌入子文档是我自然的选择。不幸的是,Ember Data仍然似乎非常依赖RAILS + SQL。 - jd.
1
是的,我认为你说得对,目前Ember更适合关系型、规范化的模型,尽管你使用了noSQL后端,但你仍然可以按照这种方式构建你的API。这取决于你在前端想要做什么,以及这些关系是否对你有用。如果不需要,而且你只想要嵌入式无ID模型,我已经成功地使用了模型片段,我从这个 github问题中发现了它。 - Phil Hauser

1

他们应该有一个id属性,这样它们就能共存于同一数组中,并成为相同产品类型的不同项目 - 具有相同的名称(除了id之外的所有属性都相同)。

要么这样,或者您有一个表示产品类型的记录,然后有一个quantity属性来指定每种产品的数量。


这个回答更适合作为对问题的评论。它并没有回答问题,你只是要求更多的澄清。 - Timusan
答案是:它应该有一个“id”属性来区分项目。问题更多的是我在自言自语(也许这不是必要的)。 - Loz Jackson
我有一个ID属性,但仍然遇到相同的问题。使用数量方法的问题在于它以许多方式破坏了Ember Data所喜欢的简单模型。我需要为数量/产品组合单独创建一个模型。我喜欢数组方法,因为它更简单。 - jd.
1
经过进一步思考,如果您有一个具有“belongsTo”属性的“product”的“lineitem”模型,则可以为每个行项目创建一个新记录(具有单独的“id”属性),但是产品可以是相同的单个产品模型。 - Loz Jackson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接