Hi Rob, overall I am OK with the proposal.
Some comments inline
On Thu 31 May 2012 03:32:25 PM CDT, David Mansfield wrote:
> It seemed that the challenge to overcome was that Hibernate did
not
> know which aliases to use when generating the where clauses for
> filters. When filters are not allowed on subclasses (current
> situation), the alias for the root entity is used for all where
> clauses. So when FilterHelper is asked to render the filters, it does
> so with a single alias string.
> So my changes revolve around two themes:
>
> 1. Remembering the filter's associated table so that we can generate
> an appropriate alias. This was done by replacing the name->condition
> map with a list of FilterConfiguration objects. This is a new class
> and includes a qualified table name (as well as the name and
> condition, of course).
>
> 2. Passing a callback (instead of the alias string) to
> FilterHelper.render() that allows it to generate an appropriate alias
> for each filter, depending on table name. The callback is an
> implementation of a new interface, FilterAliasGenerator. The
> implementation varies by context.
The same problem exists in Criteria queries (HHH-1161) when using the
sqlRestriction. In that use case, one uses the string '{alias}' as a
placeholder in the SQL, and the engine replaces it, however as with your
problem, it always replaces with the subclass alias, and therefore
cannot be used to create a restriction on any superclass properties.
It seems a more generic approach to the '{alias}' syntax which allows
for, perhaps, '{entityName.alias}' (e.g.
'{com.example.Mammal.alias}.is_pregnant = 1' would work, then your
filter conditions wouldn't need the "table" attribute, and the fix would
possibly be extensible for HHH-1161.
To be honest, I still think an embedded hint for the alias placement is
a good idea. There is a lot of chicanery in Hibernate code to try to
figure out the correct place to put aliases in sql fragments.
Something like this removes that ambiguity:
@OneToMany(mappedBy="club")
@Filters({
@Filter(name="iqMin", table="ZOOLOGY_HUMAN",
condition="{alias}.HUMAN_IQ >= :min"),
@Filter(name="pregnantMembers", table="ZOOLOGY_MAMMAL",
condition="{alias}.IS_PREGNANT=1")
})
private Set<Human> members = new HashSet<Human>();
Its really 2 different concerns.
Alternatively, there are already some annotations which take an
entity
directly (such as @ManyToOne), as a class reference, which is way more
typesafe and refactoring friendly. So instead of
"table='ZOOLOGY_MAMMAL'" you could have
"entity=Mammal.class". This
would require more bookeeping on the implementation side, but would be a
superior abstraction IMHO.
It would need to allow a mix of both I think. The Class reference is a
good alternative for inheritance as initially discussed here. But
another place this comes up is in regards to SecondaryTables, and there
we would need to know the table name.
--
steve(a)hibernate.org
http://hibernate.org