Java: 保存具有多对多关联的实体

huangapple go评论67阅读模式
英文:

Java: saving entities with ManyToMany association

问题

我在保存具有ManyToMany关联的实体时遇到了问题。我已经阅读了一些关于此的帖子,但没有得出结论。
我有两个具有ManyToMany关联的实体。我阅读到创建这些实体的正确方法是在它们之间创建关联,而不是创建一个第三个实体来保存关联,因此我按照这种方式实现了它。当我运行代码时,它按预期创建了第三个FK表,但是当我尝试保存具有此关联的新对象时,会发生以下两种情况之一:

- 在第一个示例中,我首先创建RawMaterial实体,然后创建Product实体。此操作返回错误:org.hibernate.PersistentObjectException:传递了已分离实体以持久化;
- 在第二个示例中,我首先创建Product实体。然后我创建RawMaterial实体并保存它。它成功地在数据库中创建了两行,但在FK表中没有创建任何关联。

我的代码如下:

Product实体:

@Entity
@Table(name = "products")
public class Product {

    //产品属性
    ...

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "product_raw_material",
        joinColumns = @JoinColumn(name = "raw_material_id"),
        inverseJoinColumns = @JoinColumn(name = "product_id"))
    private Set<RawMaterial> rawMaterialList = new HashSet<>();
    //Getter和Setter
}

RawMaterial实体:

@Entity
@Table(name = "raw_materials",
    uniqueConstraints = {@UniqueConstraint(columnNames = 
    {"bar_code"}),
    @UniqueConstraint(columnNames = {"name"})})
public class RawMaterial {
    
     //原材料属性
     ...
    
    @ManyToMany(mappedBy = "rawMaterialList")
    private Set<Product> productsList = new HashSet<>();

    //Getter和Setter
}

*尝试创建新的Product和RawMaterial实体:*

RawMaterial material = new RawMaterial("barcode", "name", 
    LocalDateTime.now(), 
    LocalDateTime.now());
Set<RawMaterial> materialsList = new HashSet<>();
RawMaterial savedMaterial = rawMaterialRepository.save(material);
materialsList.add(savedMaterial);

Product product = new Product("code", "name", materialsList, 
    LocalDateTime.now(), LocalDateTime.now());
Product savedProduct = productRepository.save(product);

**此示例在尝试持久化Product实体时返回错误:** org.hibernate.PersistentObjectException:传递了已分离实体以持久化。

第二次尝试:

Product product = new Product("code", "name", null, 
    LocalDateTime.now(), 
    LocalDateTime.now());
Product savedProduct = productRepository.save(product);

Set<Product> productsSet = new HashSet<>();
productsSet.add(savedProduct);
RawMaterial material = new RawMaterial("barcode", "name", 
    LocalDateTime.now(), 
    LocalDateTime.now());
material.getProductsList().add(productsSet.stream()
    .iterator().next());
rawMaterialRapository.save(material);

这会在每个表上创建一个新条目,但在关联表上(自动生成的product_raw_material关联表)上不会创建任何内容。

我不知道是否应该指定一个实体来保存关联,或者是否在repository上漏掉了一些东西。谢谢您的帮助。
英文:

I'm having trouble saving entities with ManyToMany associations. I've read some posts regarding this but came to no conclusion.
I have tow entities with ManyToMany association. I've read that the correct way to create this entities was creating the association between them and not create a third entity to hold the association, so I implemented it this way. When I run the code, it creates a third FK table as expected, but when I try to save new objects with this association it happens one of two things:

  • In the first example I create the RawMaterial entity first and, then, I create the Product entity. This action returns the error: org.hibernate.PersistentObjectException: detached entity passed to persist;
  • The second example, I create the Product entity first. Then I create the RawMaterial entity and save it. It successfully creates both lines on database but it doesn't create any association on the FK table.

My code is:

Product entity:

@Entity
@Table(name = &quot;products&quot;)
public class Product {

    //Product attributes
    ...

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = &quot;product_raw_material&quot;,
        joinColumns = @JoinColumn(name = &quot;raw_material_id&quot;),
        inverseJoinColumns = @JoinColumn(name = &quot;product_id&quot;))
    private Set&lt;RawMaterial&gt; rawMaterialList = new HashSet&lt;&gt;();
    //Getters and setters
}

RawMaterial entity:

@Entity
@Table(name = &quot;raw_materials&quot;,
    uniqueConstraints = {@UniqueConstraint(columnNames = 
    {&quot;bar_code&quot;}),
    @UniqueConstraint(columnNames = {&quot;name&quot;})})
public class RawMaterial {
    
     //RawMaterial attributes
     ...
    
    @ManyToMany(mappedBy = &quot;rawMaterialList&quot;)
    private Set&lt;Product&gt; productsList = new HashSet&lt;&gt;();

    //Getters and setters

}

First attempt to create new Product and RawMaterial entities:

RawMaterial material = new RawMaterial(&quot;barcode&quot;, &quot;name&quot;, 
    LocalDateTime.now(), 
    LocalDateTime.now());
Set&lt;RawMaterial&gt; materialsList = new HashSet&lt;&gt;();
RawMaterial savedMaterial = rawMaterialRepository.save(material);
materialsList.add(savedMaterial);

Product product = new Product(&quot;code&quot;, &quot;name&quot;, materialsList, 
    LocalDateTime.now(), LocalDateTime.now());
Product savedProduct = productRepository.save(product);

This example returns the error when trying to persist the Product entity: org.hibernate.PersistentObjectException: detached entity passed to persist.

Second attempt:

Product product = new Product(&quot;code&quot;, &quot;name&quot;, null, 
    LocalDateTime.now(), 
    LocalDateTime.now());
Product savedProduct = productRepository.save(product);

Set&lt;Product&gt; productsSet = new HashSet&lt;&gt;();
productsSet.add(savedProduct);
RawMaterial material = new RawMaterial(&quot;barcode&quot;, &quot;name&quot;, 
    LocalDateTime.now(), 
    LocalDateTime.now());
material.getProductsList().add(productsSet.stream()
    .iterator().next());
rawMaterialRapository.save(material);

This creates a new entry on each table but creates nothing on the association table (the product_raw_material association table that was automatically generated).

I don't know if I should specify an entity to hold the association or if I'm missing something on repository. Thanks for your help.

答案1

得分: 2

请尝试这样做:

    @Transactional
    public Product saveProduct() {
        RawMaterial material = new RawMaterial("条形码", "名称",
            LocalDateTime.now(),
            LocalDateTime.now());

        Set<RawMaterial> materialsList = new HashSet<>();
        materialsList.add(material);

        Product product = new Product("编码", "名称", materialsList,
            LocalDateTime.now(), LocalDateTime.now());
        material.getProductsList().add(product);

        return productRepository.save(product);
    }
英文:

Try this

@Transactional
public Product saveProduct() {
    RawMaterial material = new RawMaterial(&quot;barcode&quot;, &quot;name&quot;, 
        LocalDateTime.now(), 
        LocalDateTime.now());

    Set&lt;RawMaterial&gt; materialsList = new HashSet&lt;&gt;();
    materialsList.add(material);

    Product product = new Product(&quot;code&quot;, &quot;name&quot;, materialsList, 
        LocalDateTime.now(), LocalDateTime.now());
    material.getProductsList().add(product);

    return productRepository.save(product);
}

答案2

得分: 0

根据您的设计,关联的所有者是 RawMaterial,因为您在 mappedBy 属性中使用了 RawMaterial。这是可以的,但是当您想持久化 RawMaterial 时,它会尝试执行其职责(创建 product_raw_material 并插入具有关联双方外键的行),但没有可用的 Product 记录可供使用。这就是您描述的错误的原因。

英文:

In your design the owner of the association is RawMaterial
because of you used mappedBy attribute as RawMaterial. That's fine but when you want to persist RawMaterial it tries to execute what is responsible for (creating product_raw_material and inserting row with FKs of association sides) but there is no Product record which can be used. That's why you get the error you describe.

huangapple
  • 本文由 发表于 2020年9月21日 19:13:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/63991124.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定