I'm using Hibernate 3.6.7-Final and Spring 3.0.5.
I have entity like this
@Entity
public class Foo {
@ManyToOne
private Bar bar;
}
@Entity
public class Bar {
@Column
String group;
}
How can I use @Filter
in Foo where I want to get all Foo
's that have Bar
with group = :group
? This is supposed to be a security constraint.
Tryied just setting @Filter(name = "groupFilter", condition = "group = :group")
at the attribute bar
fromFoo
but it didn't work. Does hibernate have support for this or Filter only works at entity/collection level? Will I have to change all my HQLs to add this security constraint?
First, you have to create the @FilterDef somewhere (this defines the available parameters, and the default condition), then define the @Filter on a particular class.
Finally, have to enable the filter on the Session object, and set any parameters it requires. Filters are not enabled in hibernate sessions by default. You have to enable the specific ones you want once the session is opened.
See section 19.1 for an example: 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 ... {
}
Then somewhere in your dao code:
session.enableFilter("groupFilter").setParameter("group", group);
You should not have to touch any hql. Whenn you enable the filter, all classes which have an actual @Filter defined for it will automatically apply the condition.
There are additional ways to do things for collections, and i suggest you read the documentation referenced above for that. But in general, you can provide the @Filter annotation classes and on collection properties.
The problem with using filters with @ManyToOne
join comes from the following.
I'm referring to Hibernate 4.3.10 as this is what I have to look at.
The relevant SQL fragment is generated by class org.hibernate.engine.internal.JoinSequence
, method 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 );
Depending on the defined relationship join.getAssociationType()
returns CollectionType
or EntityType
.
The former stands for declaration like:
@OneToMany
private List<MyEntity> myEntities;
The latter stands for this one:
@ManyToOne
private MyEntity myEntity;
In the first case this method is used:
@Override
public String getOnCondition(
String alias,
SessionFactoryImplementor factory,
Map enabledFilters,
Set<String> treatAsDeclarations) {
return getAssociatedJoinable( factory ).filterFragment( alias, enabledFilters, treatAsDeclarations );
}
while in the second case the method looks like:
@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 );
}
}
This means that:
- when we have a list of referenced sub-entities in definition of an
entity, filter is unconditionally applied.
- when we have a single referenced sub-entity, filter is applied
when certain conditions are (not) met.
Based on the code, I think that filters can be applied in case of @ManyToOne
relationship when:
- in referenced entity we use a field
which is not a primary key, or
- TREAT operator is used (see, for example, here or here)