微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

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

productproduct_option_group 是 N:M 关系。我正在使用 disabled_datetime 列实现软删除,并希望从 ProductOptionGroup 实体过滤 Product 的集合。 This post 使用 @ManyToMany@Where 来实现这一点。我跟着它工作了(禁用的 product_option_group 被过滤了)。请注意 @Where 类上的 ProductOptionGroup

// `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;

    ...
}

但我想对 @OnetoMany 表使用 product-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 {
    ...
}

但是 @Where 注释将不再起作用,因此还选择了禁用的 product_option_group。如何解决这个问题?

解决方法

原因是 FooBar 不知道关联的 Bar 是否被软删除。您可以向 @Where 集合中添加另一个 FooBar 子句。类似于以下内容(我猜你的一些映射,查询可能不准确,但想法是编写一个 HQL 来过滤):

@OneToMany(mappedBy = "id.foo")
@Where(clause="not exists(select * from bar where bar_id = id and disabledDatetime is not null)")
private final Set<FooBar> fooBars = new HashSet<>();

其他解决方案是将 disabledDatetime 传播到 FooBar 并使用另一个简单的 @Where,但除了手动之外,我找不到任何其他方法可以做到这一点。

,

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

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

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;
@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();

    ...
}

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

  • 一个实体的多个集合。修改时必须小心。
  • 同一张桌子上有 2 个不同的实体。编排这些可能很困难(equals()hashCode())。
  • 添加视图。更改架构时最好小心。

也许我可以使用 Updatable and Insertable Views,但我仍然需要 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;
    }
    
    ...
}

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

  • 无论product-product_option_group如何,它都会从disabled_datetime表中选择每一行。
  • 创建另一个集合。修改时必须小心。
  • javax.persistence.EntityNotFoundException: Unable to find with id xxx 可能会发生。可以通过join fetch处理麻烦实体
  • 来解决
,

WHERE 子句为 FROM-SELECT 结构添加了过滤功能。在任何 JPQL 查询中,从数据库中检索选择性对象都是必不可少的。在我看来,您应该检查@where 的正确实现,请参阅以下reference

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。