【问题标题】:JPA - @OneToMany - Maintaining relations - Dereferencing old Object when setting new OneJPA - @OneToMany - 维护关系 - 设置新对象时取消引用旧对象
【发布时间】:2014-07-20 15:01:34
【问题描述】:

我对@9​​87654323@-Relation 有疑问。我正在使用 EclipseLink 2.5,我正在尝试维护双方,并希望根据 linkthis 直接在 @Entity-Classes 中实现这一点。

所以,我有ProductManufacturer,其中Manufacturer 可以有Products 的列表,Product 有一个Manufacturer。我想实现,您可以更改ProductManufacturer。因此将调用Product-Class 的setManufacturer()-Method:

public void setManufacturer(Manufacturer manufacturer) {

    if (this.manufacturer != null) {
        this.manufacturer.removeProduct(this);
    }

    this.manufacturer = manufacturer;
    manufacturer.addProduct(this);
}

所以,如果ProductManufacturernull,我们只需将Product 添加到productsManufacturer 列表中。到这里一切正常。

但是如果Product 已经有Manufacturer,然后有人更改了Manufactuer,我想从旧Manufacturer 的列表中删除Product。因此setter中的if-statement,它应该保持关系。

然后问题是,当我保存产品并返回到列出所有ProductsManufacturer 的页面时,我更改了ProductManufacturer 出现在两个Manufacturers 中。它不会从旧版本中删除。

如何在@Entity-Class 中解决这个问题?我想我必须在旧的Manufacturer 上调用merge()-Method,但我无法访问其中的EntityManager。而在Controller 上执行此操作似乎不是很好的代码。

所以。嗯。这让我快疯了。我希望你能明白我的意思。感谢您的任何提示,对于中等英语感到抱歉!

这里是两个类,我去掉了不相关的部分:

@Entity
public class Product extends ShopBaseEntity implements Serializable {

    @Getter
    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST})
    private Manufacturer manufacturer;

    public void setManufacturer(Manufacturer manufacturer) {

        if (this.manufacturer != null) {
            this.manufacturer.removeProduct(this);
        }

        this.manufacturer = manufacturer;
        manufacturer.addProduct(this);
    }
}

@Entity
public class Manufacturer extends ShopBaseEntity implements Serializable {

    public Manufacturer() {
        super();
    }

    public Manufacturer(String name) {
        super(name);
    }

    @Getter
    @Setter
    @OneToMany(mappedBy = "manufacturer")
    private List<Product> products;

    public void addProduct(Product product) {
        if (products == null) {
            products = new ArrayList<>();
        }

        if (!products.contains(product)) {
            products.add(product);
        }
    }

    public void removeProduct(Product product) {
        if (products != null) {
            products.remove(product);
        }
}

【问题讨论】:

    标签: jpa eclipselink java-ee-7


    【解决方案1】:

    不要在实体代码中这样做,在业务逻辑中这样做。

    Manufacturer manufacturer = ...;
    Product product = em.find(Product.class, productId);
    if (product.getManufacturer() != null) {
        product.getManufacturer().removeProduct(product);
    }
    product.setManufacturer(manufacturer);
    manufacturer.addProduct(product);
    
    em.merge(product);
    em.merge(manufacturer);
    

    实体代码应该只用于管理成员变量和关系。

    【讨论】:

    • 我不敢相信,这有这么多的代码,只是为了处理关系。好的,这是一种关系,它不是很复杂,但是如果我有一个包含许多关系的完整应用程序,这似乎是为了很少的结果而编写的代码太多。 Java EE 7 或 JPA 是否没有类似容器管理的关系?
    • 如果上面的代码在一个像@Stateless EJB这样的CMB中,则不需要两条合并行,因为容器在关闭事务时会自动执行合并。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-02
    • 2012-08-29
    相关资源
    最近更新 更多