-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 14 posts ] 
Author Message
 Post subject: Alias for select elements(...) ... where ?
PostPosted: Sun Aug 29, 2004 8:00 pm 
Beginner
Beginner

Joined: Sun Aug 29, 2004 7:21 pm
Posts: 26
I have a classe (Business) that holds a map of images (ImageFile) that are just compoents.
The ImageFile has a name and byte[].

In the servlet that displays only one given image, I try to select that image only given it's name, and the Business id :
Code:
select elements(business.images) from Business business where business.id='ff808081feac148000feac178cb20003' and name='logo1.gif'


This works fine until I need to add also a name property to the Business object.
Then, I get the following error :
Code:
java.sql.SQLException: ERROR:  Column reference "name" is ambiguous


Well, actually, this makes perfect sens. But I would like to avoid to make a join to get the ImageFile, as all the information are already in the ImageFile table.
I know I can fetch all the images and then filter them, but this would be quite innefective too.

I tried
Code:
where name='logo1.gif' in (select elements(business.images) from Business business where business.id='ff808081feac148000feac178cb20003')
but it can't work either as ImageFile isn't an entity (and so, I have nothing to write in the from part of the querry).

So, is there a way to specify an alias on the elements(business.images), so that I can specify that the name="..." is the one of an image ?
Or maybe I should write a completely different query ?

If the solution is in Hibernate 3, that's no problem, as we plan to migrate this prototype in a few days.

Thanks a lot,

Sylvain.

Hibernate version: 2.1.6

Mapping documents:
Code:
<hibernate-mapping>
    <class name="com.windsOfCabarete.infos.Business" table="businesses">

        <id name="unid" column="unid" type="java.lang.String">
            <generator class="uuid.hex">
            </generator>
        </id>

        <property name="name" type="java.lang.String" column="name"/>

        <map name="images" table="businesses_images" lazy="true" sort="unsorted" inverse="false" cascade="all" order-by="file_name">
              <key column="business_unid"></key>

              <index column="file_name" type="string"/>

              <composite-element class="com.seanergie.persistence.ImageFile">

                 <property name="name" type="java.lang.String" column="name"/>

                 <property name="bytes" type="binary" column="bytes"/>

              </composite-element>
        </map>
    </class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 30, 2004 4:59 pm 
Proxool Developer
Proxool Developer

Joined: Tue Aug 26, 2003 10:42 am
Posts: 373
Location: Belgium
Why don't you consider your 'ImageFile' as another persistent entity (with its own primary key) instead of a composite element. You could then safely query your db using the criteria you want.


Top
 Profile  
 
 Post subject: Reasons to keep it as a component
PostPosted: Mon Aug 30, 2004 5:14 pm 
Beginner
Beginner

Joined: Sun Aug 29, 2004 7:21 pm
Posts: 26
bertrand wrote:
Why don't you consider your 'ImageFile' as another persistent entity (with its own primary key) instead of a composite element. You could then safely query your db using the criteria you want.


The reason is that I use this class in many places, and many times, I just need one object for the class. For example, this Business entity also has an ImageFile component for the logo. And as they is just one logo, I don't need a Map or a List. It's just in embeded in the entity's table.

So, keeping it as a component seems just more convenient.
Also, if I make this class an entity, I'll have to make many subclasses when I use it in other entities (like Foo.imageFiles) to avoid storing them all in the same table.

So, the component fits very well to my needs ... until the holding entity has a name property.

But as you are an Hibernate Expert, I assume the answer to my question was No, there is no way to make an alias fo elements(business.images).
Am I right ?

Thanks for your help.

Sylvain.


Top
 Profile  
 
 Post subject: Re: Reasons to keep it as a component
PostPosted: Mon Aug 30, 2004 5:29 pm 
Proxool Developer
Proxool Developer

Joined: Tue Aug 26, 2003 10:42 am
Posts: 373
Location: Belgium
Sylvain wrote:
But as you are an Hibernate Expert, I assume the answer to my question was No, there is no way to make an alias fo elements(business.images).


I'm an 'Hibernate Expert' only by the total number of posts... it doesn't take their accuracy into account ;)

To answer your question, I don't know if Hibernate allows for what you wanna do... Using entities instead of components whould be a solution, but you already said why you don't want to use them.


Top
 Profile  
 
 Post subject: Thanks anyway
PostPosted: Mon Aug 30, 2004 6:47 pm 
Beginner
Beginner

Joined: Sun Aug 29, 2004 7:21 pm
Posts: 26
Ok.

Thanks for your help anyway !!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 30, 2004 8:37 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
You must qualify property names in HQL!


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 30, 2004 10:06 pm 
Beginner
Beginner

Joined: Sun Aug 29, 2004 7:21 pm
Posts: 26
gavin wrote:
You must qualify property names in HQL!


Yes, but how do you qualify it when the property is the one of a component held in a list, and so, isn't an entity ?

If they is no way to qualify it in HQL, can In do it with a Criteria ?

Thanks,

Sylvain


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 30, 2004 10:10 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Exactly the same way.

Code:
from Foo foo join foo.compositeElements elem where elem.bar = ....


Top
 Profile  
 
 Post subject: Bug in SQL generation for such cases
PostPosted: Wed Sep 01, 2004 3:57 pm 
Beginner
Beginner

Joined: Sun Aug 29, 2004 7:21 pm
Posts: 26
gavin wrote:
Exactly the same way.

Code:
from Foo foo join foo.compositeElements elem where elem.bar = ....

I just did that, and I have 2 problems :
    - As there is a join in the HQL, the SQL also contains the join clause (see bellow), and this is what I wanted to avoid in the first place.
    Indeed, there is enough information (parent.id and name) to query only the images table without joining the parent's table.
    But anyway, it's still better than to load the Business entity, and then fetch the Images map.
    - I think there is a bug in Hibernate when generating the SQL in such cases :
    Here is my HQL :
    Code:
    select elements(business.images) from Business business join business.images Img where business.id=:id and Img.name=:fileName

    And here is the generated SQL :
    Code:
    select images2_.title as x0_1_, images2_.name as x0_2_, images2_.bytes as x0_3_, ..., from businesses business0_ inner join businesses_images images1_ on business0_.id=images1_.business_id, businesses_images images2_ where business0_.id=images2_.business_id and ((business0_.id=? )and(images1_.name=? )) limit ?
    (the limit is set to 1).

    You see that there are 2 images alias : images1_ and images2_

    So, the images1_.name=? part of the where clause doesn't apply.
    Whatever the name is, I always get all the images for that Business entity (and always the first one with limit=1).

    But it works if I test the SQL with only one imagesx_ alias.

    So, my guess is that Hibernate has a bug for such cases.

    But another option is that elements(business.images) and business.images Img aren't linked. So Hibernate makes 2 different aliases.
    That would mean that they is no way to make an alias on a components Map/List.
    Again, it works without the join part if I do not need to try to fully qualify the name ... that is if only ImageFile has this property, and not the parent entity.
    But I understand I might just have been lucky that this worked :-(

Just for the note, I also tried the same HQL, but without the select elements(business.images) part - as it wasn't in your query - and this generates an SQL query that tries to fetch Business entities and not ImageFile components.
So, I get a ClassCastException doing that.

Thanks for your time.

Sylvain.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 01, 2004 5:38 pm 
Hibernate Team
Hibernate Team

Joined: Thu Dec 18, 2003 9:55 am
Posts: 1977
Location: France
Quote:
- I think there is a bug in Hibernate when generating the SQL in such cases :


i think you should reformulate if you want gavin to explain you why it is working like this.

_________________
Anthony,
Get value thanks to your skills: http://www.redhat.com/certification


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 01, 2004 8:22 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
This is not a bug, obviously, since "elements()" always results in a join, as does "join". And writing bug in bold doesn't make it a bug either. Please don't use that word in future.

It was quite hard to tell exactly what you are trying to do from your original post, but now I think I get it.

There is a current limitation in HQL that I can't do this:

Code:
  select c from Parent p left outer join p.children c where c.name like 'Child%'


if p.children is a composite element mapping. The workaround is that you can use this instead:


Code:
  select new Child(c.name, c.blah) from Parent p left outer join p.children c where c.name like 'Child%'


Top
 Profile  
 
 Post subject: Reformulation
PostPosted: Wed Sep 01, 2004 8:34 pm 
Beginner
Beginner

Joined: Sun Aug 29, 2004 7:21 pm
Posts: 26
You're right.

So, here is an attempt to reformulate the problem :

Let's say I have an HtmlPage entity.
To this entity, I need to attach ImageFiles.
So, I can design the following mapping :
Code:
<class name="com.acme.HtmlPage" table="pages">
        <id name="unid" column="unid" type="java.lang.String">
            <generator class="uuid.hex"></generator>
        </id>

        <property name="text" type="java.lang.String" column="text"/>

        <map name="images" table="pages_images" lazy="true" sort="unsorted" inverse="false" cascade="all" order-by="file_name">
              <key column="page_unid"></key>

              <index column="file_name" type="string"/>

              <composite-element class="com.acme.ImageFile">
                 <property name="name" type="java.lang.String" column="name"/>
                 <property name="bytes" type="binary" column="bytes"/>
              </composite-element>
        </map>
    </class>

Now, I have a servlet that renders the images, given the page id, and the file name.
I want to make the HQL query as efficient as possible, and I don't want to make the ImageFiles objects entities. I want them to remain conponents (reasons given above).

As the pages_images already has all the information to retrieve the right Image file, the following query works fine in a single fetch and without promoting the ImageFile as an entity :
Code:
select elements(page.images) from HtmlPage page where page.id=:unid and name=:name

This works but the name= in the where clause isn't well qualified ... and I don't know how to qualify it.
So, now, if I add a name property to the page, the query will fail with a java.sql.SQLException: ERROR: Column reference "name" is ambiguous.

If I try gavin's proposition :
Code:
from HtmlPage page join page.image img where page.id=:unid and img.name=:name

I get a ClassCastException, as I'm retrieving HtmlPages and not the Image.

And if I try :
Code:
select elements(page.images) from HtmlPage page join page.image img where page.id=:unid and img.name=:name
First, it generates an SQL query with a join (that could be avoided), and the query is buggy and returns ALL the images for that page.
The reason for that bug is that Hibernate doesn't understand that the the "elements(page.images)" and "pageimage as img" are the same.
So, it makes 2 aliases in the SQL, and thus, the image.name=:name part of the WHERE clause in the SQL is useless.
Here is the generated SQL, where you can see images1_ and images2_ aliases :
Code:
select images2_.name as x0_1_, images2_.bytes as x0_2_ from pages pages0_ inner join pages_images images1_ on pages0_.unid=images1_.page_unid, pages_images images2_ where pages0_.unid=images2_.page_unid and ((pages0_.unid=? )and(images1_.name=? ))


I also tried the following HQL that could solve the problem :
Code:
select elements(page.images) as img from HtmlPage page where page.id=:unid and img.name=:name
But it fails too with a QueryException : ", expected in SELECT".
As far as I understand the inner working of Hibernate, all the above problems are "normal", and I think only the last query with select elements(...)as img could solve the problem.
It doesn't seem to be supported though :-(

But as I'm still a beginner in Hibernate, I might miss an important point.

Thanks again for your help.


Top
 Profile  
 
 Post subject: I'll try that
PostPosted: Wed Sep 01, 2004 8:36 pm 
Beginner
Beginner

Joined: Sun Aug 29, 2004 7:21 pm
Posts: 26
Sorry, I think I posted my message while you where responding.

I'll try that and I'll let you know.

Thank you.


Top
 Profile  
 
 Post subject: It works.
PostPosted: Wed Sep 01, 2004 9:10 pm 
Beginner
Beginner

Joined: Sun Aug 29, 2004 7:21 pm
Posts: 26
I tried your workaround and it works.

The problem is that I find it quite a bad practice to have to embed all the Child properties in the HQL, as adding a property will involve reviewing all the HQL using this component ... but as it's a workaround, I'll live with it.

Do you plan something to avoid using this workaround in the future ?

As for the "elements()" always results in a join", I just checked my first HQL, and it doesn't make a join in the SQL :
Code:
select elements(page.images) from HtmlPage page where page.id=:unid and name=:name
but yes, this wasn't a properly written HQL.
I don't know if the extra join has an impact on the performance, as the database should have all the info to avoid it.

Thanks for your help, and don't take it bad for the bold bug.
I was just trying to explain where I think they might be a bug ... which ok, isn't there.
This library is an incredible accomplishment, and I can't imagine working without it anymore.
Congratulation also for your support, it's really outstanding !


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 14 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.