使用@Filter和@ManyToOne关系

时间:2012-05-21 19:40:31

标签: java hibernate many-to-one hibernate-filters

我正在使用Hibernate 3.6.7-Final和Spring 3.0.5。

我有这样的实体

@Entity
public class Foo {
    @ManyToOne
    private Bar bar;
}

@Entity
public class Bar {
    @Column
    String group;
}

我如何在Foo中使用@Filter我想要获得Foo Bar group = :group的所有@Filter(name = "groupFilter", condition = "group = :group")?这应该是一个安全约束。

尝试在bar的属性Foo设置{{1}}但不起作用。 Hibernate是否支持此功能,或者Filter仅适用于实体/集合级别?我是否必须更改所有HQL以添加此安全约束?

2 个答案:

答案 0 :(得分:2)

首先,您必须在某处创建@FilterDef(这定义了可用参数和默认条件),然后在特定类上定义@Filter。

最后,必须在Session对象上启用过滤器,并设置它需要的任何参数。默认情况下,在休眠会话中未启用过滤器。打开会话后,您必须启用所需的特定组件。

有关示例,请参阅第19.1节:http://docs.jboss.org/hibernate/orm/3.6/reference/en-US/html/filters.html

@FilterDef(name="groupFilter", parameters={@ParamDef( name="group", type="string" )})
@Filters(
  { @Filter(name="groupFilter", condition="group = :group") }
)
public class ... {
}

然后在你的代码中的某个地方:

session.enableFilter("groupFilter").setParameter("group", group);

你不应该触摸任何hql。当您启用过滤器时,所有为其定义了实际@Filter的类将自动应用该条件。

还有其他方法可以为集合做事,我建议您阅读上面引用的文档。但一般来说,您可以提供@Filter注释类和集合属性。

答案 1 :(得分:0)

@ManyToOne连接一起使用过滤器的问题来自以下方面。 我指的是Hibernate 4.3.10,因为这是我要看的。

相关的SQL片段是由类org.hibernate.engine.internal.JoinSequence的方法toJoinFragment生成的:

/**
 * Generate a JoinFragment
 *
 * @param enabledFilters The filters associated with the originating session to properly define join conditions
 * @param includeAllSubclassJoins Should all subclass joins be added to the rendered JoinFragment?
 * @param withClauseFragment The with clause (which represents additional join restrictions) fragment
 * @param withClauseJoinAlias The
 *
 * @return The JoinFragment
 *
 * @throws MappingException Indicates a problem access the provided metadata, or incorrect metadata
 */
public JoinFragment toJoinFragment(
        Map enabledFilters,
        boolean includeAllSubclassJoins,
        String withClauseFragment,
        String withClauseJoinAlias) throws MappingException {

        ...

        final String on = join.getAssociationType().getOnCondition( join.getAlias(), factory, enabledFilters, treatAsDeclarations );

根据定义的关系join.getAssociationType()返回CollectionTypeEntityType

前者代表声明,例如:

@OneToMany
private List<MyEntity> myEntities;

后者代表这个:

@ManyToOne
private MyEntity myEntity;

在第一种情况下,使用此方法:

@Override
public String getOnCondition(
        String alias,
        SessionFactoryImplementor factory,
        Map enabledFilters,
        Set<String> treatAsDeclarations) {
    return getAssociatedJoinable( factory ).filterFragment( alias, enabledFilters, treatAsDeclarations );
}

而在第二种情况下,方法如下:

@Override
public String getOnCondition(
        String alias,
        SessionFactoryImplementor factory,
        Map enabledFilters,
        Set<String> treatAsDeclarations) {
    if ( isReferenceToPrimaryKey() && ( treatAsDeclarations == null || treatAsDeclarations.isEmpty() ) ) {
        return "";
    }
    else {
        return getAssociatedJoinable( factory ).filterFragment( alias, enabledFilters, treatAsDeclarations );
    }
}

这意味着:

  • 当我们有一个定义中的引用子实体列表时 实体,则无条件应用过滤器。
  • 当我们有一个引用的子实体时,将应用过滤器 (不)满足某些条件时。

基于代码,我认为在以下情况下,如果存在@ManyToOne关系,则可以应用过滤器:

  • 在引用实体中,我们使用一个字段 不是主键,或者
  • 使用
  • TREAT运算符(例如,参见此处或这里)