【问题标题】:Hibernate filter does not apply for join entityHibernate 过滤器不适用于连接实体
【发布时间】:2020-09-18 08:14:19
【问题描述】:

我正在尝试了解休眠过滤器,我认为即使查询不是从过滤的实体开始,也可以应用过滤器,如果我只是加入它就可以应用。

我的实体:

@Table(name = "SPM_SECTION", schema = "TEST")
@GenericGenerator(name = "MODSEC_ID.GEN", strategy = "uuid2")
public class ModuleSection implements Serializable {

private AcademicClass academicClass;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "CLASS_ID")
    public AcademicClass getAcademicClass() {
        return academicClass;
    }

    public void setAcademicClass(AcademicClass academicClass) {
        this.academicClass = academicClass;
    }
    
}

@Entity
@GenericGenerator(name = "AC_CLASS_ID.GEN", strategy = "uuid2")
@Where(clause="1=1")
@FilterDef(name= Resources.SECURITY_FILTER_NAME, parameters={@ParamDef(name=Resources.SECURITY_FILTER_PARAMETER, type="string")})
@Filter(name=Resources.SECURITY_FILTER_NAME, condition = "DISCRIMINATOR_ID in (:"+Resources.SECURITY_FILTER_PARAMETER+")")
@Table(name = "ACADEMIC_CLASS", schema = "TEST", uniqueConstraints = @UniqueConstraint(columnNames = {"OUS_ID", "YEAR_ID",
        "PERIOD_ID", "SHIFT_ID", "SEMESTER", "CODE" }))
public class AcademicClass implements java.io.Serializable {

    //I tried by having the association here, i also tried without it.
    private Set<ModuleSection> sections = new HashSet<>(0);
    
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "academicClass")
    public Set<ModuleSection> getSections() {
        return this.sections;
    }

    public void setSections(Set<ModuleSection> sections) {
        this.sections = sections;
    }

}

通过拦截器启用过滤器,并从数据库中获取参数列表以确保安全。

当我执行这样的查询时:

em.createQuery("select acc from AcademicClass acc ...........", AcademicClass.class)
.getResultList();

应用过滤器。但我也希望在我的查询从 ModuleSection 开始时应用过滤器:

em.createQuery("select ms from ModuleSection ms join ms.academicClass acc", AcademicClass.class)
.getResultList();

在上述查询中,未应用过滤器。

ModuleSection 实体中的 AcademicClass 可以为空,但我还有其他不为空的实体,上述情况不起作用。

我还尝试在模块部分属性中应用 @Filter 或 @FilterJoinTable,但没有成功:

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "CLASS_ID")
    @Filter(name=Resources.SECURITY_FILTER_NAME, condition = "DISCRIMINATOR_ID in (:"+Resources.SECURITY_FILTER_PARAMETER+")")
    @FilterJoinTable(name=Resources.SECURITY_FILTER_NAME, condition = "DISCRIMINATOR_ID in (:"+Resources.SECURITY_FILTER_PARAMETER+")")
    public AcademicClass getAcademicClass() {
        return academicClass;
    }

我的问题: 过滤器是否仅用于过滤 from 子句中的实体?过滤器是否适用于连接实体? 如果我想实现上述内容,我是否还应该在 ModuleSection 中添加一个 DISCRIMINATOR_ID 并将过滤器添加到从那里开始查询的实体?

【问题讨论】:

  • 为什么要手动加入academicClass
  • 这是一个大查询,如果我加入已过滤的实体,我需要在其中进行过滤。以上只是一个例子。
  • 我假设 Hibernate 需要使用自己的机制来检测和应用过滤器,如果您手动创建查询,则不会使用 Hibernate 机制来构建连接,因此它们无法被过滤。
  • 所以只有当我有实体到 from 子句而不是连接时才应用过滤器?因为当实体在 from 子句中时,过滤器被正确应用。

标签: java hibernate java-ee-8 hibernate-filters


【解决方案1】:

在休眠文档中对此保持沉默,但看起来@Filter 仅适用于from 子句是真的。

假设我们有以下映射:

@Entity
@Table(name = "ACADEMIC_CLASS")
@FilterDef(
   name="isAccessible",
   parameters = @ParamDef(
      name="sec",
      type="string"
   )
)
@Filter(
   name="isAccessible",
   condition="{acClass}.discriminator_id in (:sec)",
   aliases = {
      @SqlFragmentAlias(alias = "acClass", table= "TEST_SCHEMA.ACADEMIC_CLASS")
   }
)
public class AcademicClass
{
   @Id
   @Column(name = "class_id")
   private Long id;

   @OneToMany(fetch = FetchType.LAZY, mappedBy = "academicClass")
   private Set<ModuleSection> sections;

   // getters/setters
}

@Entity
@Table(name = "SPM_SECTION")
public class ModuleSection
{
   @Id
   @Column(name = "sec_id")
   private Long id;

   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "sec_class_id")
   private AcademicClass academicClass;

   // getters/setters
}

当我们运行以下查询时:

session
   .enableFilter("isAccessible")
   .setParameter("sec", "A1");

List<AcademicClass> classes = session.createQuery(
    "select ac from ModuleSection ms join ms.academicClass ac",
    AcademicClass.class
).getResultList();

过滤器未应用。它应该发生在JoinSequence.toJoinFragment。在这种情况下,filterCondition 为空。

但对于改写方式如下查询:

List<AcademicClass> classes = session.createQuery(
    "select ac from ModuleSection ms, AcademicClass ac where ms.academicClass = ac",
    AcademicClass.class
).getResultList();

我们将拥有:

因此将生成以下查询:

Hibernate: 
/* select
     ac 
   from
      ModuleSection ms,
      AcademicClass ac 
   where
        ms.academicClass = ac
*/
select
   academiccl1_.class_id as class_id1_0_ 
from TEST_SCHEMA.SPM_SECTION modulesect0_ cross 
join TEST_SCHEMA.ACADEMIC_CLASS academiccl1_ 
where academiccl1_.discriminator_id in (?) 
  and modulesect0_.sec_class_id=academiccl1_.class_id

因此,作为一种解决方法,您可以用这种方式重写您的查询。

@FilterJoinTableannotation 只能在父实体和子表之间有链接表时使用。

【讨论】:

    猜你喜欢
    • 2012-07-20
    • 2018-10-24
    • 1970-01-01
    • 2021-06-07
    • 1970-01-01
    • 2014-03-11
    • 2021-07-07
    • 2017-10-06
    • 1970-01-01
    相关资源
    最近更新 更多