Spring JPA @OneToMany没有让孩子们坚持

时间:2017-02-25 04:41:10

标签: java spring hibernate jpa spring-data-jpa

在开始之前,我检查了几个帖子,但没有一个解决了我的问题。

请有人在这里指导我。我想建立一个工厂(1)到库存(n)关系。

我创建了几个模型,一个用于Plant,如下所示,我提到了OneToMany关系

@Entity
public class Plant implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long plantID;

@OneToMany(mappedBy = "plant", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Inventory> listInventory = new ArrayList<>();
getter and setter....

另一个关于库存的地方,我提到了ManyToOne关系

@Entity
public class Inventory implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long inventoryId;

@ManyToOne
@JoinColumn(name = "plantID", nullable = false)
private Plant plant;

当我尝试保存下面的数据时,它会保存工厂(父级),但不保存其子级。

作为持久化数据的一部分,我做了类似下面的事情

public Plant addPlant(String plantName, List<Inventory> listMaterial, PlantRepository plantRepository, InventoryRepository inventoryRepository) {
    Plant plant = new Plant();
    List<Inventory> listInventory = new ArrayList<>();
    plant.setPlantName(plantName);

    for (Inventory inventory : listMaterial) {
        inventory.setPlant(plant);
        listInventory.add(inventory);
    }
    plant.setListInventory(listInventory);
    return plantRepository.save(plant);
}

在阅读了几篇文章之后,我发现我应该在持续之前设置工厂与库存的关联。所以我确实添加了相同的代码,但它继续无限或只是我的STS被绞死。

我确信我做错了但不确定在哪里。请有人指导我完成。

我的期望是库存将是一个参考表,我将在其中列出库存清单。当我添加一个新工厂时,我会将一些库存映射到这个工厂。同样,许多工厂和许多库存都会发生这种情况。

作为持久性的一部分,我将不得不节省工厂及其库存。我还应该能够传递工厂ID并检索相应的库存。

更新1: 此外,我不确定我使用的关系对于这种情况是否足够公平。由于我的库存是参考表,同时,当工厂映射到多个库存时,可以在持久化之前修改每个库存。

我尝试了@ManyToMany,它将关系存储在第3个表中,并且对这两个表都有唯一的引用,但是我无法获得每个库存记录的详细信息。 使用@ManyToMany,当我获取它时,带来参考表中的值,而不是与父(植物)一起保存的修改后的值请任何建议

更新2

我尝试使用相同的模型,但我改变了我保存数据的方式,如下所示。

public Plant addPlant(String plantName, List<Inventory> listMaterial, PlantRepository plantRepository, InventoryRepository inventoryRepository) {
Plant plant = new Plant();
List<Inventory> listInventory = new ArrayList<>();
plant.setPlantName(plantName);

for (Inventory inventory : listMaterial) {
    plant.addInventoryToPlant(inventory);
}

return plantRepository.save(plant);

}

这是我工厂模型中的添加方法

public void addInventoryToPlant(Inventory inventory) {
    listInventory.add(inventory);
    inventory.setPlant(this);
}

它只是用不同的工厂ID覆盖库存表,但不创建引用表或连接表来维护所有可能的映射。如果我尝试添加具有2个库存的工厂,则会将它们首先映射到库存表。如果我添加另一个植物,那么这将被覆盖。我假设它将创建第三个表来维护这个实体

2 个答案:

答案 0 :(得分:1)

我感觉这些库存实体是分离的,而持久性提供程序在刷新期间没有考虑它们。你没有得到异常,因为@OneToMany是flush算法中的一种特殊关系,因为持久拥有实体的行为不依赖于目标,因此Hibernate将继续并仅持久保存Plant实体。

尝试使用merge而不是persist:

plant.setListInventory(listInventory);
return plantRepository.merge(plant);

<强>更新

您还可以使用save进行逐个合并每个库存,因为Spring JPA会隐式检查实体是应该保存还是合并:

for (Inventory inventory : listMaterial) {
     Inventory mergedInventory = inventoryRepository.save(inventory);
     mergedInventory.setPlant(plant);
     listInventory.add(mergedInventory);
}

plant.setListInventory(listInventory);
return plantRepository.save(plant);

答案 1 :(得分:1)

这回答了 UPDATE 2 部分:

据我了解,PlantInventory属于多对多关系,但还有其他属性需要与特定Plant的信息一起存储持有特定的Inventory项目。

在这种情况下,您需要一个额外的实体(让我们称之为StockItem),用于保存该附加状态。然后,PlantInventory都将与新实体处于一对多的关系中。

您的映射将变为:

class Plant {
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "plant_id")
    private Set<StockItem> stockItems;
    ...
}

class StockItem {
    @ManyToOne(mappedBy = "stockItems")
    private Plant plant;

    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST})
    @JoinColumn(name = "inventory_id")
    private Inventory inventory;

    //put any fields here that may vary from one plant to plant to another
    private int quantity;

}

class Inventory {
    @OneToMany(mappedBy = "inventory")
    public Set<StockItem> stockItems;

    // leave any fields that will NOT vary from one plant to another here
    private String name;
}

注意事项:

  • 此映射假定您要向StockItem添加新的Plant(JPA会忽略添加到Inventory.stockItems的新项目),在这种情况下,它将会足以将StockItem.inventory字段设置为正确的值,将StockItem添加到Plant.stockItems列表,然后保存Plant实体

  • StockItem.plantInventory.stockItems并非绝对必要,如果您不需要,请将其删除