spring boot - 如何将多对一实体保存到数据库

spring boot - how to save many-to-one entities to database

this spring boot app中,我有一个从CartItemone-to-many映射,其中序列化周期通过忽略Item中的Cart来解决=]的序列化。 (因此 Item 中的 Cart 字段带有 @JsonBackReference 注释)

Spring 引导成功初始化数据库,这样 GET-ing 所有 Carts 给出 json

[
    {
        "id": 1, <-- cart 1
        "items": [
            {
                "id": 0, <-- item 0
                "itemName": "tooth brush"
            },
            {
                "id": 1,
                "itemName": "shampoo"
            }
        ]
    },
    {
        "id": 2,
        "items": [
            {
                "id": 2,
                "itemName": "body wash"
            }
        ]
    },
    {
        "id": 3,
        "items": []
    }
]

然而,当我想将 Item 添加到现有的 Cart 时,新的 Item 被保存为 null

@PostMapping("carts/{cartId}")
    public Cart addItemToCart(@PathVariable("cartId") long cartId, @RequestBody Item item)
    {
        LOG.info("Trying to add ITEM: id={}, name={}, cart={} to CART: {}", item.getId(), item.getItemName(), item.getCart(), cartId);

        Cart cart = dao.getById(cartId);
        LOG.info("I) CART: id={}, items={}", cart.getId(),cart.getItems().stream().map(i -> i.getItemName()).collect(Collectors.toList()));

        // also tried at this location: item.setCart(cart);
        cart.getItems().add(item);
        LOG.info("II) CART: id={}, items={}", cart.getId(),cart.getItems().stream().map(i -> i.getItemName()).collect(Collectors.toList()));

        Cart res = dao.save(cart); // HERE CART SAVES NEW ITEM AS NULL
        LOG.info("III) CART: id={}, items={}", res.getId(),res.getItems().stream().map(i -> i.getItemName()).collect(Collectors.toList()));

        Cart resCheck = dao.getById(res.getId());
        LOG.info("IV) CART: id={}, items={}", resCheck.getId(),resCheck.getItems().stream().map(i -> i.getItemName()).collect(Collectors.toList()));
        return res;
    }

假设我想将名称为 "beer" 的 Item 添加到名称为 cartid=1Cart。在我看来,我只需要 json 中的 itemName 因为 Cart 字段被忽略 (@JsonBackReference) 并且 itemid 是自动生成的。

那么,发布

{
    "itemName":"beer"
}

localhost:9200/demo/api/carts/1给出日志(对比上面代码)

Trying to add ITEM: id=0, name=beer, cart=null to CART: 1
I) CART: id=1, items=[tooth brush, shampoo]
II) CART: id=1, items=[tooth brush, beer, shampoo]
III) CART: id=1, items=[null, tooth brush, shampoo] <-- beer itemName is null after dao.save()
IV) CART: id=1, items=[null, tooth brush, shampoo]

这并不奇怪,因为 Carts 和 Items 是在 cartid 上连接的,但是序列化时啤酒 Item 应该从哪里得到 cartid Item 忽略任何 Cart 信息!如果我 POST

什么也不起作用
{
    "itemName":"beer",
    "cart":{
        "id":1,
        "items":[]
    }
}

这也将新项目保存为空。

真正想要避免的是切换JsonBackReferenceJsonManagedReference

我怎样才能将 Item 添加到 Cart

这是实体类

@Entity
@Table(name="items")
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Item
{
    @Id
    @GenericGenerator(name="itemIdGen" , strategy="increment")
    @GeneratedValue(generator="itemIdGen")
    @Column(name = "itemid", nullable=false)
    private long id;

    @Column(name="itemname")
    private String itemName;

    @ManyToOne
    @JoinColumn(name = "cartid", nullable=false)
    @JsonBackReference
    private Cart cart;
    /*...*/
}

@Entity
@Table(name="carts")
public class Cart 
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "cartid", nullable=false)
    private long id;

    @Column(name="items")
    @OneToMany(mappedBy = "cart")
    @JsonManagedReference
    private Set<Item> items;
    /*..*/
}

感谢您的帮助

P.S.: 如果你想克隆开头链接的 repo,你还需要 运行 eureka server and clone the demo-commons 项目。

解决方案是忘记在 Item 中引用整个 Cart 对象,而只保留 cartid(在其上合并)

@Entity
@Table(name="carts")
public class Cart 
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "cartid", nullable=false)
    private long id;

//  @Column(name="items")
//    @OneToMany(mappedBy = "cart")
//  @JsonManagedReference
//    private Set<Item> items;
    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name="cartid", referencedColumnName="cartid")
    private Set<Item> items;
    /*..*/
}

@Entity
@Table(name="items")
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Item
{
    @Id
    @GenericGenerator(name="itemIdGen" , strategy="increment")
    @GeneratedValue(generator="itemIdGen")
    @Column(name = "itemid", nullable=false)
    private long id;

    @Column(name="itemname")
    private String itemName;

//    @ManyToOne
//    @JoinColumn(name = "cartid", nullable=false)
//    @JsonBackReference
//    private Cart cart;
    @Column(name="cartid")
    private Long cartId;
    /*..*/
 }

现在我可以快乐地POST Item

{
    "itemName":"beer",
    "cartid":1
}