Restricting Returned Types in Polymorphic Queries

10 views
Skip to first unread message

Neal Blomfield

unread,
Sep 16, 2008, 11:14:49 PM9/16/08
to nhusers
If I have an inheritance hierarchy like:

Answer (abstract)
|--> TextAnswer (abstract)
| |--> ShortTextAnswer
| |--> LongTextAnswer
|--> OptionAnswer (abstract)
|--> SelectManyOptionsAnswer
|--> SelectOneOptionAnswer
|--> RatingScaleAnswer
|--> YesNoAnswer

and I query against the SelectOneOptionAnswer, how do I restrict the
results to only contain SelectOneOptionAnswer instnaces and not any
derived classes (RatingScaleAnswer / YesNoAnswer)?

Ayende Rahien

unread,
Sep 17, 2008, 1:23:21 AM9/17/08
to nhu...@googlegroups.com
I think that you can use ".class" property to determain that

Matt

unread,
Sep 17, 2008, 1:11:36 PM9/17/08
to nhusers
.class will work on the root, it produces buggy code when used on a
join.

e.g. this won't work:
from Cat as cat inner join cat.Kittens as kitten
where kitten.class = 'Core.FiveLeggedKitten'

On Sep 17, 6:23 am, "Ayende Rahien" <aye...@ayende.com> wrote:
> I think that you can use ".class" property to determain that
>

Ayende Rahien

unread,
Sep 17, 2008, 1:18:30 PM9/17/08
to nhu...@googlegroups.com
what is the sql generated/

Neal Blomfield

unread,
Sep 17, 2008, 4:33:45 PM9/17/08
to nhusers
I have been trying to use Restrictions.Eq( "class",
typeof(SelectOneOptionAnswer)) but this gives me an error as it is
expecting an int rather than a string.

Confirmed this using something similar to the following criteria:

DetachedCriteria criteria =
DetachedCriteria.For<SelectOneOptionAnswer>();
criteria.SetProjection( Projections.ProjectionList()
.Add( Projections.Property("Id"))
.Add( Projections.Property("class"));

Mapping returned Ids to types, the results I get back are:
SelectOneOptionAnswer = 3
RatingScaleAnswer = 5
YesNoAnswer = 6

Running two similar queries across ShortTextAnswer and LongTextAnswer
returns class = 1 for the ShortTextAnswer and class = 2 for the
LongTextAnswer.

The HQL "from SelectOneOptionAnswer where SelectOneOptionAnswer.class
= 'SelectOneOptionAnswer'" produces the following SQL (using SQLite as
the backing db for these tests)

select
selectoneo0_.Id as Id13_,
selectoneo0_1_.Version as Version13_,
selectoneo0_1_.TheQuestion as TheQuest3_13_,
selectoneo0_1_.Comments as Comments13_,
selectoneo0_.SelectedOption as Selected2_16_,
case
when selectoneo0_2_.Id is not null then 5
when selectoneo0_3_.Id is not null then 6
when selectoneo0_.Id is not null then 3
end as clazz_
from
SelectOneOptionAnswer selectoneo0_
inner join Answer selectoneo0_1_ on
selectoneo0_.Id=selectoneo0_1_.Id
left outer join RatingScaleAnswer selectoneo0_2_ on
selectoneo0_.Id=selectoneo0_2_.Id
left outer join YesNoAnswer selectoneo0_3_ on
selectoneo0_.Id=selectoneo0_3_.Id
where
(SelectOneOptionAnswer.class='SelectOneOptionAnswer' )

and errors as there is no class property of SelectOneOptionAnswer in
the database.

Will try updating to trunk and see if that fixes the issue otherwise I
will create an isolated test case to confirm this behaviour and then
figure out where to submit the bug =)

Thanks for the help everyone.


On Sep 18, 5:18 am, "Ayende Rahien" <aye...@ayende.com> wrote:
> what is the sql generated/
>

Fabio Maulo

unread,
Sep 17, 2008, 4:50:40 PM9/17/08
to nhu...@googlegroups.com
s.CreateQuery("from SelectOneOptionAnswer so where so.class = SelectOneOptionAnswer").List();
You must use the class name without enclose it in quote and you must use alias for the class you are quering.

2008/9/17 Neal Blomfield <Neal.Bl...@gmail.com>



--
Fabio Maulo

Fabio Maulo

unread,
Sep 17, 2008, 4:54:24 PM9/17/08
to nhu...@googlegroups.com
Sorry ... to be more clear perhaps is better an example using parameter
s.CreateQuery("from SelectOneOptionAnswer so where so.class = :pConcreteClass").SetParameter("pConcreteClass", typeof(SelectOneOptionAnswer).FullName, NHibernateUtil.ClassMetaType).List();

Bye.
Fabio Maulo

Tuna Toksöz

unread,
Sep 17, 2008, 4:58:32 PM9/17/08
to nhu...@googlegroups.com
So you say there is no support for it in Criteria Api.
--
Tuna Toksöz

Typos included to enhance the readers attention!

Ayende Rahien

unread,
Sep 17, 2008, 5:16:59 PM9/17/08
to nhu...@googlegroups.com
Yes, there is, but likely using the discriminator values, from what posted so far.
I think the same approach would work for Criteria API as well, though.

Fabio Maulo

unread,
Sep 17, 2008, 5:17:16 PM9/17/08
to nhu...@googlegroups.com
2008/9/17 Tuna Toksöz <teh...@gmail.com>

So you say there is no support for it in Criteria Api.

If I well remember we don't have a Restriction to query concreteClass implementation using Criteria.
BTW I don't know if our friend need a Dynamic-Query... if not HQL is more than enough.
--
Fabio Maulo

Fabio Maulo

unread,
Sep 17, 2008, 5:26:30 PM9/17/08
to nhu...@googlegroups.com
Ok... using Criteria API
s.CreateCriteria(typeof(SelectOneOptionAnswer), "so")
.Add(Property.ForName("sp.class")
.Eq(typeof(SelectOneOptionAnswer)
.List();

You know... I'm not a Criteria fan and I use it only when I need a dynamic-query and, in some cases, I prefer use HQL with dynamic-query too (only because, for me, is more easy to read and some other stuff....).

--
Fabio Maulo

Fabio Maulo

unread,
Sep 17, 2008, 5:28:33 PM9/17/08
to nhu...@googlegroups.com
ups... I forgot some paren... (hope google add some plug-in to check C# code in emails ;)  hahaha )

2008/9/17 Fabio Maulo <fabio...@gmail.com>



--
Fabio Maulo

Ken Egozi

unread,
Sep 17, 2008, 5:28:36 PM9/17/08
to nhu...@googlegroups.com
for the sake of the original inquirer - in the last snippet "sp" and "so" got mixed up.
anyway the point is that you can get to the .class property through Property.ForName

Tuna Toksöz

unread,
Sep 17, 2008, 5:32:31 PM9/17/08
to nhu...@googlegroups.com
Cool, I didn't know that. Thanks!


On Thu, Sep 18, 2008 at 12:26 AM, Fabio Maulo <fabio...@gmail.com> wrote:

Neal Blomfield

unread,
Sep 17, 2008, 6:01:36 PM9/17/08
to nhusers
Brilliant. Thank you Fabio, updated query as shown and now it all
works like a charm.

Fabio Maulo

unread,
Sep 17, 2008, 6:02:50 PM9/17/08
to nhu...@googlegroups.com
2008/9/17 Ken Egozi <ego...@gmail.com>

for the sake of the original inquirer - in the last snippet "sp" and "so" got mixed up.
anyway the point is that you can get to the .class property through Property.ForName

:) Ken better than a compiler....
--
Fabio Maulo

Ken Egozi

unread,
Sep 18, 2008, 2:10:46 AM9/18/08
to nhu...@googlegroups.com
I am trained to spot spaces-instead-of-tabs in patch files ...
Reply all
Reply to author
Forward
0 new messages