Using @Filter with @ManyToOne relationship
I am using Hibernate 3.6.7-Final and Spring 3.0.5.
I have an object 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
that have Bar
with group = :group
? This is assumed to be a security limitation.
Trying to just set @Filter(name = "groupFilter", condition = "group = :group")
in attribute Bar
from Foo
, but that didn't work. Does hibernate have support or does the filter only work at the entity / collection level? Do I have to change all of my HQLs to add this security constraint?
source to share
First you need to create a @FilterDef somewhere (this defines the available options and default condition), then define @Filter for a specific class.
Finally, you need to enable the filter on the Session object and set any required parameters. Filters are not enabled on hibernate sessions by default. You have to enable the specific ones you want after opening a session.
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 don't need to touch any hql. When you enable a filter, all classes that have an actual @Filter defined for it will automatically apply this condition.
There are additional ways to do things for collections, and I suggest you read the documentation above. But in general, you can provide @Filter annotation classes and collection properties.
source to share
The problem of using filters with union is @ManyToOne
as follows. I mean Hibernate 4.3.10 as this is what I should be looking at.
The corresponding SQL fragment is generated by the 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 );
join.getAssociationType()
Returns CollectionType
or, depending on the relationship EntityType
.
The first means a declaration:
@OneToMany
private List<MyEntity> myEntities;
The latter stands for this:
@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 this:
@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 );
}
}
It means that:
- when we have a list of specified entities in the entity definition, the filter is applied unconditionally.
- when we have one specified child entity, the filter is applied when certain conditions are (not) met.
Based on the code, I think that filters can be applied in a relationship case @ManyToOne
when:
source to share