如何使用 Spring Data JPA(Hibernate) 跨映射表过滤关联实体?

use*_*379 6 hibernate jpa soft-delete spring-data-jpa spring-boot

有没有办法在中间实体(映射表)中使用@OneToMany和过滤软删除的多对多关联@ManyToOne

product并且product_option_group是 N:M 关系。我正在使用该disabled_datetime列实现软删除,并希望ProductOptionGroupProduct实体中过滤一个集合。这篇文章正在使用@ManyToMany@Where实现这一目标。我跟着,它工作(禁用product_option_groups 被过滤)。需要注意@WhereProductOptionGroup类。

// `product` <-> `product-product_option_group` <-> `product_option_group`

@Entity
@Table(name = "product")
public class Product implements Serializable {
    ...

    @ManyToMany
    @JoinTable(name = "product-product_option_group",
            joinColumns = @JoinColumn(name = "product_id"),
            inverseJoinColumns = @JoinColumn(name = "product_option_group_id"))
    private final Set<ProductOptionGroup> productOptionGroups = new HashSet<>();

    ...
}

@Entity
@Table(name = "product_option_group")
@Where(clause = "disabled_datetime is null")
public class ProductOptionGroup implements Serializable {
    ...

    @Column(name = "disabled_datetime")
    private ZonedDateTime disabledDatetime;

    ...
}
Run Code Online (Sandbox Code Playgroud)

但我想用@OneToManyproduct-product_option_group桌子上,就像这样。

@Entity
@Table(name = "product")
public class Product implements Serializable {
    ...

    @OneToMany(mappedBy = "id.product")
    private final Set<ProductProductOptionGroup> productProductOptionGroups = new HashSet<>();

    ...
}

@Entity
@Table(name = "`product-product_option_group`")
public class ProductProductOptionGroup implements Serializable {
    @EmbeddedId
    private final ProductProductOptionGroupId id = new ProductProductOptionGroupId();

    ...
}

@Embeddable
public class ProductProductOptionGroupId implements Serializable {
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    @JoinColumn(name = "product_id", referencedColumnName = "id")
    private Product product;

    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    @JoinColumn(name = "product_option_group_id", referencedColumnName = "id")
    @Where(clause = "disabled_datetime is null")
    private ProductOptionGroup productOptionGroup;
}

@Entity
@Table(name = "product_option_group")
@Where(clause = "disabled_datetime is null")
public class ProductOptionGroup implements Serializable {
    ...
}
Run Code Online (Sandbox Code Playgroud)

但随后@Where注释将不再起作用,因此product_option_group也选择了 disabled s。如何解决这个问题?

use*_*379 0

我想在等待答案时添加解决方法。

首先,我可以添加一个视图作为过滤器。

CREATE VIEW `product-product_option_group-enabled` AS
SELECT *
FROM `product-product_option_group` ppog
JOIN product_option_group pog ON ppog.product_option_group_id = pog.id
    AND pog.disabled_datetime IS NULL;
Run Code Online (Sandbox Code Playgroud)
@Entity
@Table(name = "`product-product_option_group-enabled`") // using the view as a filter
public class ProductProductOptionGroupEnabled implements Serializable {
    @EmbeddedId
    private final ProductProductOptionGroupId id = new ProductProductOptionGroupId();

    ...
}
Run Code Online (Sandbox Code Playgroud)

然后用于ProductProductOptionGroupEnabled读取和ProductProductOptionGroup任何数据修改可能会解决问题。我不喜欢这个。

  • 一个实体的多个集合。修改的时候一定要小心。
  • 同一张表上有 2 个不同的实体。协调这些可能很困难(equals()并且hashCode())。
  • 添加视图。更改架构时最好小心。

也许我可以利用可更新和可插入视图,但我仍然需要ProductProductOptionGroup选择每一行。


其次,我可以从 Java 中过滤集合。

@Entity
@Table(name = "product")
public class Product implements Serializable {
    ...

    @OneToMany(mappedBy = "id.product")
    private final Set<ProductProductOptionGroup> productProductOptionGroups = new HashSet<>();

    public Set<ProductProductOptionGroup> getProductProductOptionGroups() {
        return productProductOptionGroups.stream()
                .filter(o -> o.getId().getProductOptionGroup().getDisabledDatetime() == null)
                .collect(Collectors.toSet());
    }

    public Set<ProductProductOptionGroup> getProductProductOptionGroupsAll() {
        return productProductOptionGroups;
    }
    
    ...
}
Run Code Online (Sandbox Code Playgroud)

然后使用getProductProductOptionGroups()来获取过滤后的集合。我也不喜欢这个。

  • 它将选择product-product_option_group表中的每一行,而不管disabled_datetime.
  • 创建另一个集合。修改的时候一定要小心。
  • javax.persistence.EntityNotFoundException: Unable to find with id xxx可能发生。可以通过join fetching 问题实体来解决