休眠过滤器不适用于联接实体

问题描述

我试图理解休眠过滤器,我认为即使查询不是从已过滤实体开始的,过滤器仍适用,并且只要我加入该过滤器就可以应用。

我的实体:

@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可为空,但在上述情况不起作用的情况下,我还有其他不为null的实体。

我也尝试在模块部分的属性中应用@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并将过滤器添加到该实体,从那里开始查询

解决方法

休眠文档中对此没有任何说明,但是@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();

我们将拥有:

enter image description here

,结果将生成以下查询:

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

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

@FilterJoinTable annotation仅在父实体和子实体之间具有链接表时才能使用。